Init
This commit is contained in:
18
.kubeconfig
Normal file
18
.kubeconfig
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
clusters:
|
||||||
|
- cluster:
|
||||||
|
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJY1R6R0hSU3FrblF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TmpBek1qUXdNREExTXpOYUZ3MHpOakF6TWpFd01ERXdNek5hTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUUN2aVFqN0Z0dVhpZlZRYURtNUNNYmxNYXFaMXJXVGZDMk5SSEJWcVN4M0YxS1IzWlpRZ1J3YjZ5eSsKbU5FLzRZV2ZOK1NJUVEvbG93Y2llMXZxLzl6QTFNaXY4enM0YlRQaU5sY0hRTm9iYkRiUHBUNkNVdXpvdjdqRgpqbXhiQ3BlNlhpSmlTVHQvT3h6Wlg3NzZiUVAvNkxUTEdtdm1xaWxTa0I4Rjl6eVlFRmJrbkVYQkp1UHBXY0pUCkdCUmpyMzJzS05RbE13c2thSFhnNmVsRzhVa1FFMDNQeUpITi8yazlNZWpVWmVwQll2VE1mKzZCMW56ZDdVWWoKKzA2Z3EzWUhlUDE3R0kxVjRzR0UwMDJ3a1RsS213UUNiV1p2NkZMRHl3M01hL0RWdGFjQ0pQMklVeFhHeCs3agowRE0wZXZMN2ZMUnNGbGtSNGl2U09VcmJIamlQQWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJSNjE3TXZ0L01uQXR0aHZXZHZoTWxMcEs3MDZ6QVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQWczVmNNUVFYcQpxSXNhd1RxOXByM05oY282Zk83U3g0MkNncXZXZzFIMXYxR1hiNVMzaDlaaUN1cVF4MkUvT0lNSmdUdytNblY5ClNZMVJKZ1Qvc0RGQk5jQ3ZLM1ZPVmpCdmFmRUh3b3V4dTlGSzdTaityaWJ4STNod3dsNFVrSit6Ly93ZWl0L0IKMXRWSXE5Y1lLblhFck9sQmJ1KzZYR3phTmRzOVBPSGZwU2g3ZWlhTFVZemNDaXN3b2NQN0NVdE53bUViekVZNwpLRFZKclJSWEtTNTdtYnNXSlpnWVFEZGlDVzMvNkI4TUg1YTVoakdjempadjBNc2hsVmtuWWlNL3RrbEExdWxCCi9TM2ZXdnhuallicWlWcXJDbzRMSFhwV0tHbFdyY1ZtSFJVcnZ1ZjlYQ09ncEhyUnRVVHFOOFVUQy95MXN0eDAKZjAzcHd0aGZXSU8rCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||||
|
server: https://127.0.0.1:39209
|
||||||
|
name: kind-kupyter
|
||||||
|
contexts:
|
||||||
|
- context:
|
||||||
|
cluster: kind-kupyter
|
||||||
|
user: kind-kupyter
|
||||||
|
name: kind-kupyter
|
||||||
|
current-context: kind-kupyter
|
||||||
|
kind: Config
|
||||||
|
users:
|
||||||
|
- name: kind-kupyter
|
||||||
|
user:
|
||||||
|
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLVENDQWhHZ0F3SUJBZ0lJT0xIdlBuY3E1VWN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TmpBek1qUXdNREExTXpOYUZ3MHlOekF6TWpRd01ERXdNek5hTUR3eApIekFkQmdOVkJBb1RGbXQxWW1WaFpHMDZZMngxYzNSbGNpMWhaRzFwYm5NeEdUQVhCZ05WQkFNVEVHdDFZbVZ5CmJtVjBaWE10WVdSdGFXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDdFRVMzgKYXFqTzVlbG5hclhRUWxDcEZiTDNHSnpVY0lhY2ROeHV5NzFZUitEZmc2bEdJK3puQlFVTlpYOXhpak5TbHlZNgpiQ00rQk9IR09vVGxsdUxhL1RXbWNaUnhYYVBCeVpHY3ZkWVJCNFNVT2JlZ1BwT0xjajFBaXdvbU9IQUVOYXNzClZUeFlEcXlOUnd5M1cwNGFVcWNMREMyVUtDU0hEUVk1dlphOWo4MXpkdjl0K0g5L2RZb1diM3RHOTVySlRndE0KUGhhcDZkNlpoVUVXSDl1aE5Ha2YreE01Zi9KaUVRNnovWmc1alBsdHVHcGhaSUR5QmhUcUJaZnNJTjN3UllreQpiRnp6SndMZTZVVmhRQlE2YjVjZjlHYXVndWVocmFLb0wxUThJVFJuR2JvR0ZEb3dUbkQwaGN1V0RqZi9QbnV2CnZIUWk4L0pqK3pKcDBWek5BZ01CQUFHalZqQlVNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUsKQmdnckJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRkhyWHN5KzM4eWNDMjJHOQpaMitFeVV1a3J2VHJNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNXUHhIdDJpM0ZERHkyd3JOeDBJZkFLYUF3CldWMzVCNTcxblVNTWltNVFjalVMUEU1c0praEpra3VGNGRZTlU5amM4K0c1WHF6QnpyQlpBajg5dWI3UmM2MXAKbVpQekEvWHlUbjZBK1BBRFBBRlkxSE9FMmdtSmd4eFZjV08rRmtyRzBZN1pjemRQdzdJRjQySzFDYzVSMDU1TApENjNGMkhaWEQ5d3NYWC8zYS9ReWpuMlFFN0dXOWc4MTUya1lMeVYycGN3cVo5aTFRNlgyUjBzbXRiOEt4UFZDCkdhS2ZwKy9NVXdZOE40WHdOakIraVo5anVvWU1mR095TFBieGIzTThMblR3bkRxNHdRRjV5c24vVFJQWCtFNHAKbnFCblNXbDVSVzdERi9VVi9na0pIbDlxWTJydFlEZkkyWHJ5YzJKdVhUSTh3N1BjRi80QVlFQnQvQkZXCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||||
|
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBclUxTi9HcW96dVhwWjJxMTBFSlFxUld5OXhpYzFIQ0duSFRjYnN1OVdFZmczNE9wClJpUHM1d1VGRFdWL2NZb3pVcGNtT213alBnVGh4anFFNVpiaTJ2MDFwbkdVY1YyandjbVJuTDNXRVFlRWxEbTMKb0Q2VGkzSTlRSXNLSmpod0JEV3JMRlU4V0E2c2pVY010MXRPR2xLbkN3d3RsQ2draHcwR09iMld2WS9OYzNiLwpiZmgvZjNXS0ZtOTdSdmVheVU0TFRENFdxZW5lbVlWQkZoL2JvVFJwSC9zVE9YL3lZaEVPcy8yWU9ZejViYmhxCllXU0E4Z1lVNmdXWDdDRGQ4RVdKTW14Yzh5Y0MzdWxGWVVBVU9tK1hIL1Jtcm9Mbm9hMmlxQzlVUENFMFp4bTYKQmhRNk1FNXc5SVhMbGc0My96NTdyN3gwSXZQeVkvc3lhZEZjelFJREFRQUJBb0lCQUFLSjMxcVROV1hTZUZqTApkMTVWbWxqZnVIOW1IT1gvdi9rS3ZTL2lUQ08rNmN4Y1lWNWxxRks2QUJqeUk2dkdHbnBiUEhRZW9XV0hMTWQ2CmsvZkkvZ20zSzlJRVYraFJOdFRmM3dJc3hiWDZKamNGb1dyM2Y3SExPcHAzYnU2Z1pRT3F4WmNncUlHaHRXVmMKWlJOS2d4cGZtNUxOMnQwUXVYaEErSlpmOEpWV1A3OHFsaUNFQ2ZEd3pCRVpRVHVoYmhwRGhvNjBxL0UzU3RQVQprTGMzVitONnFEK0szeTZpM0hWU3lldkpYWWg0RXJCNlY1RTVweU5wZU90d1BhbThVRG91ZWZpcFZJQkVWVHhvCm00NVNCanZSQnRRYWRxMGN5M0p0L3N3aEtJQUVpT0c2WE1icmc4bzFWSDRNNnJiWmlQdDBiODVOUVJNd0FuR2kKMUsrTU9RRUNnWUVBeWtWMFZlSmdObS8rSVVsblRscGgzOENKd3kydU5QVXBRSHBoQ3pjVUxkQXV0Ri8yNTgvTwpJeVBoMVB5bzNCOXBLVVdmYnRpVjJoZjhXUjV3UjdJakpLWDhzaHRqcEs3TkJvTDhrdnBRUVl0QS9CVS9KR2E0ClRKaWpsbGJNOWtXYzF2dEs5YStQV255U3hCb1psb0hYaE1lRzFMK2JpRE5FcFk4c2hTbzVkTU1DZ1lFQTIxWHIKNnRuelhSRGVtMzdRRmttOXpUL01tSmROQ3MxOVovU2kvNGVRTHpKNkM2RlJUMGNFTHpHVjA3SXdIYjhMZ1JPTwpUY2g3V3RXYngwa2o4L2RVcXNJWXpLYzRhT2hsVVg2aUNpZVZBakdETzg2aFVWT3FkTmVXaFZudDdyZE95cTgxCmtNdkdTTmV6ZlFTMnE0cU1GQVUwcGpVdDQwaiszWFdJdVdvRWp5OENnWUVBbmtzc2QrbnBFYkVqV0RseHQwZlUKUUo4Vk1NR1hDNnF3MWR6d0JTN2RnOXpnTUJqSnlUQS9TaERTc3pQbmtoeWkxOEc4dTZxVDIxSGFFb1JYcWtRbQpiSS9aNmlpMUdqUVNEMzZDMnlNNW01RzNFWkF2RWZXeFZZQSt4WEM0aGlLRVUxbmxsOUFFaC9QbGg4SkZOQnY0CjVkaWdFKzYvY1I5dUlZS2lmTFJHc3JFQ2dZQmZ3cXFtdFpPSURXWnpVekY4bWFOeGFpcGtjS0psVmdRcmorWmUKVkF5Q1hySmtRNEVoY0tzR0E4c2JTdyt3M1FranlLcjNrTkV5ZmxKdDlxUG96eEk3SDFUK2ZQK201ZGZlZGNBLwpXTHE0NDI4ZGZJQjM1bVJrY1ArNXB1SzN0M2FDRFc4QWtjYzNaRjFyOXRQZUh6WTdRMjZTSm1PcmVPSTFSQ3gyCmJ6QWdad0tCZ1FDNUlhVTdzWmlrVVlwbmZJYUZKK1NGTTN4b1lIWVpzNHYvN0t5OEhCM2VqVHlZbXl1QjBZNFYKUDhqZlg4SUxsN0o3a3dKNGpnd2kyWGZxckorOW9SRzZ0N0I5R3EyM3pUR29rSnJXSFRKeXJOcnpUalRRT1A2LwpTNERObWgrM1Mxd1MxTC9IY25VZk1uUmFnMEtraTFIQ0ExdFQzK3Q1a254dWxxYldOUlUyVUE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
||||||
10
Dockerfile.hub
Normal file
10
Dockerfile.hub
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
FROM quay.io/jupyterhub/k8s-hub:4.3.2
|
||||||
|
|
||||||
|
USER root
|
||||||
|
RUN apt-get update && apt-get install -y nodejs npm && apt-get clean
|
||||||
|
|
||||||
|
USER jovyan
|
||||||
|
RUN pip install --upgrade pip
|
||||||
|
RUN pip install git+https://github.com/jupyter/nbgrader.git@main ngshare_exchange
|
||||||
|
|
||||||
|
COPY ./kupyter-notebook/nbgrader_config.py /etc/jupyter/nbgrader_config.py
|
||||||
89
config.yaml
Normal file
89
config.yaml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
hub:
|
||||||
|
image:
|
||||||
|
name: localhost/kupyter-hub
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: Never
|
||||||
|
|
||||||
|
services:
|
||||||
|
ngshare:
|
||||||
|
url: http://ngshare.jupyterhub.svc.cluster.local:8080
|
||||||
|
apiToken: 822235aaaf83f0232c799fe948cbb1594b01d7d7b11af051871cc2d3fcb08fe8
|
||||||
|
ngshare-admin:
|
||||||
|
apiToken: setuptoken123456789012345678901234567890123456789012345678901234
|
||||||
|
|
||||||
|
|
||||||
|
db:
|
||||||
|
type: postgres
|
||||||
|
url: postgresql+psycopg2://jupyterhub:jupyterhub@jupyterhub-db-postgresql.jupyterhub.svc:5432/jupyterhub
|
||||||
|
|
||||||
|
config:
|
||||||
|
JupyterHub:
|
||||||
|
authenticator_class: nativeauthenticator.NativeAuthenticator
|
||||||
|
admin_users:
|
||||||
|
- admin
|
||||||
|
- instructor-Prog
|
||||||
|
- instructor-Sig
|
||||||
|
|
||||||
|
NativeAuthenticator:
|
||||||
|
open_signup: false
|
||||||
|
allowed_users:
|
||||||
|
- admin
|
||||||
|
- instructor-Prog
|
||||||
|
- instructor-Sig
|
||||||
|
|
||||||
|
extraVolumes:
|
||||||
|
- name: hub-logos
|
||||||
|
configMap:
|
||||||
|
name: hub-logos
|
||||||
|
|
||||||
|
extraVolumeMounts:
|
||||||
|
- name: hub-logos
|
||||||
|
mountPath: /usr/local/share/jupyterhub/static/images/jupyterhub-80.png
|
||||||
|
subPath: jupyterhub-80.png
|
||||||
|
- name: hub-logos
|
||||||
|
mountPath: /usr/local/share/jupyterhub/static/images/jupyterhub.svg
|
||||||
|
subPath: jupyterhub.svg
|
||||||
|
|
||||||
|
extraConfig:
|
||||||
|
ngshare.py: |
|
||||||
|
c.JupyterHub.services.append({
|
||||||
|
'name': 'ngshare',
|
||||||
|
'url': 'http://ngshare.jupyterhub.svc.cluster.local:8080',
|
||||||
|
'api_token': '822235aaaf83f0232c799fe948cbb1594b01d7d7b11af051871cc2d3fcb08fe8',
|
||||||
|
'oauth_no_confirm': True})
|
||||||
|
nbgrader: |
|
||||||
|
c.JupyterHub.load_groups = {
|
||||||
|
"formgrader-users": ["admin"]
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy:
|
||||||
|
secretToken: "8031b6dca309ff7259a10d1d38c70c4852d17d5bab02c31cbe7d76a3fb60cb66"
|
||||||
|
|
||||||
|
prePuller:
|
||||||
|
hook:
|
||||||
|
enabled: false
|
||||||
|
continuous:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
cull:
|
||||||
|
enabled: true
|
||||||
|
timeout: 1800
|
||||||
|
every: 300
|
||||||
|
|
||||||
|
singleuser:
|
||||||
|
defaultUrl: "/tree"
|
||||||
|
image:
|
||||||
|
name: localhost/kupyter-notebook
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: Never
|
||||||
|
memory:
|
||||||
|
limit: 1G
|
||||||
|
guarantee: 256M
|
||||||
|
cpu:
|
||||||
|
limit: 1
|
||||||
|
guarantee: 0.1
|
||||||
|
cloudMetadata:
|
||||||
|
blockWithIptables: false
|
||||||
|
networkPolicy:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1773734432,
|
||||||
|
"narHash": "sha256-IF5ppUWh6gHGHYDbtVUyhwy/i7D261P7fWD1bPefOsw=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "cda48547b432e8d3b18b4180ba07473762ec8558",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
318
flake.nix
Normal file
318
flake.nix
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
{
|
||||||
|
description = "kupyter – rootless Kubernetes dev shell";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
|
||||||
|
get-all = pkgs.writeShellApplication {
|
||||||
|
name = "get-all";
|
||||||
|
runtimeInputs = [ pkgs.kubectl ];
|
||||||
|
text = ''kubectl get pods -A'';
|
||||||
|
};
|
||||||
|
|
||||||
|
cluster-start = pkgs.writeShellApplication {
|
||||||
|
name = "cluster-start";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.kind
|
||||||
|
pkgs.kubectl
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
kind create cluster --name kupyter --wait 60s
|
||||||
|
kubectl config use-context kind-kupyter
|
||||||
|
echo "✓ Cluster ready"
|
||||||
|
kubectl cluster-info
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
cluster-stop = pkgs.writeShellApplication {
|
||||||
|
name = "cluster-stop";
|
||||||
|
runtimeInputs = [ pkgs.kind ];
|
||||||
|
text = ''
|
||||||
|
kind delete cluster --name kupyter
|
||||||
|
rm -f .kubeconfig
|
||||||
|
echo "✓ Cluster deleted, kubeconfig cleared"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
tls-init = pkgs.writeShellApplication {
|
||||||
|
name = "tls-init";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.openssl
|
||||||
|
pkgs.kubectl
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||||
|
-keyout tls.key \
|
||||||
|
-out tls.crt \
|
||||||
|
-subj "/CN=jupyterhub.local/O=kupyter"
|
||||||
|
|
||||||
|
kubectl create namespace jupyterhub --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
kubectl create secret tls jupyterhub-tls \
|
||||||
|
--cert=tls.crt \
|
||||||
|
--key=tls.key \
|
||||||
|
--namespace jupyterhub
|
||||||
|
echo "✓ TLS secret stored in jupyterhub namespace"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
helm-repos = pkgs.writeShellApplication {
|
||||||
|
name = "helm-repos";
|
||||||
|
runtimeInputs = [ pkgs.kubernetes-helm ];
|
||||||
|
text = ''
|
||||||
|
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
|
||||||
|
helm repo add jupyterhub https://hub.jupyter.org/helm-chart/
|
||||||
|
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||||
|
helm repo add ngshare https://libretexts.github.io/ngshare-helm-repo/
|
||||||
|
helm repo add prometheus https://prometheus-community.github.io/helm-charts
|
||||||
|
helm repo update
|
||||||
|
echo "✓ all helm repos added and updated"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ingress-install = pkgs.writeShellApplication {
|
||||||
|
name = "ingress-install";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.kubernetes-helm
|
||||||
|
pkgs.kubectl
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
|
||||||
|
--namespace ingress-nginx \
|
||||||
|
--create-namespace \
|
||||||
|
--set controller.service.type=NodePort \
|
||||||
|
--set controller.service.nodePorts.http=30080 \
|
||||||
|
--set controller.service.nodePorts.https=30443
|
||||||
|
echo "✓ ingress-nginx installed"
|
||||||
|
kubectl get pods -n ingress-nginx
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
jupyterhub-install = pkgs.writeShellApplication {
|
||||||
|
name = "jupyterhub-install";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.kubernetes-helm
|
||||||
|
pkgs.kubectl
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
kubectl create namespace jupyterhub --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
kubectl create configmap hub-logos \
|
||||||
|
--from-file=jupyterhub-80.png=./kupyter-notebook/logo.png \
|
||||||
|
--from-file=jupyterhub.svg=./kupyter-notebook/logo.svg \
|
||||||
|
--namespace jupyterhub \
|
||||||
|
--dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
helm upgrade --install jupyterhub jupyterhub/jupyterhub \
|
||||||
|
--namespace jupyterhub \
|
||||||
|
--values config.yaml
|
||||||
|
|
||||||
|
kubectl apply -f jupyterhub-ingress.yaml
|
||||||
|
echo "✓ jupyterhub installing"
|
||||||
|
kubectl get pods -n jupyterhub
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
db-install = pkgs.writeShellApplication {
|
||||||
|
name = "db-install";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.kubernetes-helm
|
||||||
|
pkgs.kubectl
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
helm upgrade --install jupyterhub-db bitnami/postgresql \
|
||||||
|
--namespace jupyterhub \
|
||||||
|
--set auth.username=jupyterhub \
|
||||||
|
--set auth.password=jupyterhub \
|
||||||
|
--set auth.database=jupyterhub
|
||||||
|
echo "✓ postgres installing"
|
||||||
|
kubectl get pods -n jupyterhub
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
notebook-build = pkgs.writeShellApplication {
|
||||||
|
name = "notebook-build";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.podman
|
||||||
|
pkgs.kind
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
podman build -t kupyter-notebook:latest ./kupyter-notebook
|
||||||
|
podman save kupyter-notebook:latest -o /tmp/kupyter-notebook.tar
|
||||||
|
kind load image-archive /tmp/kupyter-notebook.tar --name kupyter
|
||||||
|
rm /tmp/kupyter-notebook.tar
|
||||||
|
echo "✓ image built and loaded into cluster"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
hub-build = pkgs.writeShellApplication {
|
||||||
|
name = "hub-build";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.podman
|
||||||
|
pkgs.kind
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
podman build -t kupyter-hub:latest -f Dockerfile.hub .
|
||||||
|
podman save kupyter-hub:latest -o /tmp/kupyter-hub.tar
|
||||||
|
kind load image-archive /tmp/kupyter-hub.tar --name kupyter
|
||||||
|
rm /tmp/kupyter-hub.tar
|
||||||
|
echo "✓ hub image built and loaded"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ngshare-install = pkgs.writeShellApplication {
|
||||||
|
name = "ngshare-install";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.kubernetes-helm
|
||||||
|
pkgs.kubectl
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
helm upgrade --install ngshare ngshare/ngshare \
|
||||||
|
--namespace jupyterhub \
|
||||||
|
--set ngshare.token=822235aaaf83f0232c799fe948cbb1594b01d7d7b11af051871cc2d3fcb08fe8 \
|
||||||
|
--set ngshare.hub_api_token=822235aaaf83f0232c799fe948cbb1594b01d7d7b11af051871cc2d3fcb08fe8 \
|
||||||
|
--set ngshare.admins="admin,ngshare-setup" \
|
||||||
|
--values ngshare-values.yaml
|
||||||
|
|
||||||
|
echo "Waiting for ngshare..."
|
||||||
|
kubectl wait pod \
|
||||||
|
--for=condition=ready \
|
||||||
|
--selector=app.kubernetes.io/name=ngshare \
|
||||||
|
--namespace jupyterhub \
|
||||||
|
--timeout=120s
|
||||||
|
|
||||||
|
echo "✓ ngshare installed"
|
||||||
|
kubectl get pods -n jupyterhub
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ngshare-courses = pkgs.writeShellApplication {
|
||||||
|
name = "ngshare-courses";
|
||||||
|
runtimeInputs = [ pkgs.kubectl ];
|
||||||
|
text = ''
|
||||||
|
HUB_POD=$(kubectl get pod -n jupyterhub -l component=hub -o name)
|
||||||
|
|
||||||
|
kubectl exec -n jupyterhub "$HUB_POD" -- curl -s -X POST \
|
||||||
|
"http://ngshare.jupyterhub.svc.cluster.local:8080/services/ngshare/course/Programmieren" \
|
||||||
|
-d "instructors=[\"instructor-Prog\"]" \
|
||||||
|
-H "Authorization: token setuptoken123456789012345678901234567890123456789012345678901234"
|
||||||
|
|
||||||
|
kubectl exec -n jupyterhub "$HUB_POD" -- curl -s -X POST \
|
||||||
|
"http://ngshare.jupyterhub.svc.cluster.local:8080/services/ngshare/course/Signale" \
|
||||||
|
-d "instructors=[\"instructor-Sig\"]" \
|
||||||
|
-H "Authorization: token setuptoken123456789012345678901234567890123456789012345678901234"
|
||||||
|
|
||||||
|
echo "✓ courses created"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
monitoring-install = pkgs.writeShellApplication {
|
||||||
|
name = "monitoring-install";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.kubernetes-helm
|
||||||
|
pkgs.kubectl
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
helm upgrade --install kube-prometheus-stack prometheus/kube-prometheus-stack \
|
||||||
|
--namespace monitoring \
|
||||||
|
--create-namespace \
|
||||||
|
--wait
|
||||||
|
kubectl apply -f ./jupyterhub-monitor.yaml
|
||||||
|
echo "✓ monitoring installed"
|
||||||
|
kubectl get pods -n monitoring
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
rebuild-all = pkgs.writeShellApplication {
|
||||||
|
name = "rebuild-all";
|
||||||
|
runtimeInputs = [
|
||||||
|
pkgs.kind
|
||||||
|
pkgs.kubectl
|
||||||
|
pkgs.kubernetes-helm
|
||||||
|
pkgs.podman
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
cluster-stop
|
||||||
|
cluster-start
|
||||||
|
tls-init
|
||||||
|
helm-repos
|
||||||
|
ingress-install
|
||||||
|
hub-build
|
||||||
|
notebook-build
|
||||||
|
db-install
|
||||||
|
ngshare-install
|
||||||
|
jupyterhub-install
|
||||||
|
monitoring-install
|
||||||
|
echo "Waiting for hub to be ready..."
|
||||||
|
kubectl wait pod \
|
||||||
|
--for=condition=ready \
|
||||||
|
--selector=component=hub \
|
||||||
|
--namespace jupyterhub \
|
||||||
|
--timeout=300s
|
||||||
|
ngshare-courses
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
name = "kupyter";
|
||||||
|
|
||||||
|
packages = [
|
||||||
|
get-all
|
||||||
|
cluster-start
|
||||||
|
cluster-stop
|
||||||
|
tls-init
|
||||||
|
helm-repos
|
||||||
|
ingress-install
|
||||||
|
jupyterhub-install
|
||||||
|
notebook-build
|
||||||
|
db-install
|
||||||
|
ngshare-install
|
||||||
|
ngshare-courses
|
||||||
|
hub-build
|
||||||
|
monitoring-install
|
||||||
|
rebuild-all
|
||||||
|
pkgs.openssl
|
||||||
|
pkgs.kubectl
|
||||||
|
pkgs.kubernetes-helm
|
||||||
|
pkgs.podman
|
||||||
|
pkgs.kind
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export KUBECONFIG="$(pwd)/.kubeconfig"
|
||||||
|
export KIND_EXPERIMENTAL_PROVIDER=podman
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " kupyter dev shell"
|
||||||
|
echo " KUBECONFIG → $(pwd)/.kubeconfig (session-local)"
|
||||||
|
echo " runtime → podman (rootless)"
|
||||||
|
echo ""
|
||||||
|
echo " cluster-start # create cluster"
|
||||||
|
echo " cluster-stop # delete cluster + wipe kubeconfig"
|
||||||
|
echo " tls-init # generate self-signed cert"
|
||||||
|
echo " helm-repos # add and update helm repos"
|
||||||
|
echo " ingress-install # install nginx ingress"
|
||||||
|
echo " notebook-build # build and load notebook image"
|
||||||
|
echo " jupyterhub-install # install jupyterhub"
|
||||||
|
echo " get-all # show all pods"
|
||||||
|
echo ""
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
8
hub-logo-configmap.yaml
Normal file
8
hub-logo-configmap.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: hub-logos
|
||||||
|
namespace: jupyterhub
|
||||||
|
binaryData:
|
||||||
|
jupyterhub-80.png: ""
|
||||||
|
jupyterhub.svg: ""
|
||||||
21
jupyterhub-ingress.yaml
Normal file
21
jupyterhub-ingress.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: jupyterhub
|
||||||
|
namespace: jupyterhub
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||||
|
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: jupyterhub.local
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: proxy-public
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
20
jupyterhub-monitor.yaml
Normal file
20
jupyterhub-monitor.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
name: jupyterhub
|
||||||
|
namespace: monitoring
|
||||||
|
labels:
|
||||||
|
release: kube-prometheus-stack
|
||||||
|
spec:
|
||||||
|
namespaceSelector:
|
||||||
|
matchNames:
|
||||||
|
- jupyterhub
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
component: hub
|
||||||
|
app: jupyterhub
|
||||||
|
release: jupyterhub
|
||||||
|
endpoints:
|
||||||
|
- port: hub
|
||||||
|
path: /hub/metrics
|
||||||
|
interval: 30s
|
||||||
7
kind-config-resolved.yaml
Normal file
7
kind-config-resolved.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
kind: Cluster
|
||||||
|
apiVersion: kind.x-k8s.io/v1alpha4
|
||||||
|
name: kupyter
|
||||||
|
containerdConfigPatches:
|
||||||
|
- |-
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"]
|
||||||
|
endpoint = ["http://10.89.2.2:5000"]
|
||||||
16
kind-config.yaml
Normal file
16
kind-config.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
kind: Cluster
|
||||||
|
apiVersion: kind.x-k8s.io/v1alpha4
|
||||||
|
name: kupyter
|
||||||
|
nodes:
|
||||||
|
- role: control-plane
|
||||||
|
extraPortMappings:
|
||||||
|
- containerPort: 80
|
||||||
|
hostPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
- containerPort: 443
|
||||||
|
hostPort: 443
|
||||||
|
protocol: TCP
|
||||||
|
containerdConfigPatches:
|
||||||
|
- |-
|
||||||
|
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"]
|
||||||
|
endpoint = ["http://REGISTRY_IP:5000"]
|
||||||
9
kupyter-notebook/Dockerfile
Normal file
9
kupyter-notebook/Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FROM jupyter/datascience-notebook:latest
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
|
||||||
|
COPY nbgrader_config.py /etc/jupyter/nbgrader_config.py
|
||||||
|
|
||||||
|
COPY logo.png /opt/conda/lib/python3.13/site-packages/nbclassic/static/base/images/logo.png
|
||||||
|
COPY logo.png /opt/conda/lib/python3.13/site-packages/jupyter_server/static/logo/logo.png
|
||||||
BIN
kupyter-notebook/logo.png
Normal file
BIN
kupyter-notebook/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
198
kupyter-notebook/logo.svg
Normal file
198
kupyter-notebook/logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 108 KiB |
11
kupyter-notebook/nbgrader_config.py
Normal file
11
kupyter-notebook/nbgrader_config.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from ngshare_exchange import configureExchange
|
||||||
|
|
||||||
|
c = get_config()
|
||||||
|
|
||||||
|
configureExchange(
|
||||||
|
c, "http://ngshare.jupyterhub.svc.cluster.local:8080/services/ngshare"
|
||||||
|
)
|
||||||
|
|
||||||
|
c.CourseDirectory.course_id = "*"
|
||||||
|
|
||||||
|
c.FormgradeApp.base_url = "/user/{username}/"
|
||||||
7
kupyter-notebook/requirements.txt
Normal file
7
kupyter-notebook/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
folium
|
||||||
|
seaborn
|
||||||
|
#tensorflow
|
||||||
|
#torch
|
||||||
|
nbgrader
|
||||||
|
ngshare_exchange
|
||||||
|
rise
|
||||||
9
nbgrader_config.hub.py
Normal file
9
nbgrader_config.hub.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from ngshare_exchange import configureExchange
|
||||||
|
|
||||||
|
c = get_config()
|
||||||
|
|
||||||
|
configureExchange(
|
||||||
|
c, "http://ngshare.jupyterhub.svc.cluster.local:8080/services/ngshare"
|
||||||
|
)
|
||||||
|
|
||||||
|
c.CourseDirectory.course_id = "*"
|
||||||
6
ngshare-values.yaml
Normal file
6
ngshare-values.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
pvc:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
|
||||||
|
ngshare:
|
||||||
|
debug: true
|
||||||
20
tls.crt
Normal file
20
tls.crt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDOzCCAiOgAwIBAgIUdweHytW9S6NYnsg8qQC7qkXrSAkwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwLTEZMBcGA1UEAwwQanVweXRlcmh1Yi5sb2NhbDEQMA4GA1UECgwHa3VweXRl
|
||||||
|
cjAeFw0yNjAzMjQwMDExMjJaFw0yNzAzMjQwMDExMjJaMC0xGTAXBgNVBAMMEGp1
|
||||||
|
cHl0ZXJodWIubG9jYWwxEDAOBgNVBAoMB2t1cHl0ZXIwggEiMA0GCSqGSIb3DQEB
|
||||||
|
AQUAA4IBDwAwggEKAoIBAQCsSo1M0tgSqAwEFQ2XY8qJIdhFvJojTj2mK18gizfS
|
||||||
|
Egn9whTynbKX6+AxRRlH+TQ8TQ91IYXGpZJaAXnxpwwC1X9qjeqrKFoI9927Bgp2
|
||||||
|
1CzK8dI2Q7DZPTeSgAAW79dSjApwxqiw+Dy+PP1REe94UvKg/PQezN8Zy3V4+c9F
|
||||||
|
7noVgUp/xEWPsVwsH84uX2XI7HyHv4t3sMAzqD4d/41GoJX8FZwwK5IKuIyiNVJo
|
||||||
|
y2UUjcG7qXUUBUXuOcpyW0l9zwRsDtqp6mqXj4+VCdLHKYP/X/mftLK+cwhzNvN5
|
||||||
|
uWooZf78igN7rFp1n6cvmIUuQEUnnPGkwBfbZSFK0l7NAgMBAAGjUzBRMB0GA1Ud
|
||||||
|
DgQWBBRA0biw83Xcib+sQcIypsreXfv9oDAfBgNVHSMEGDAWgBRA0biw83Xcib+s
|
||||||
|
QcIypsreXfv9oDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB5
|
||||||
|
ufcXwO0iKoXkPkAoVXEz4xs0uGQ6Q4nq23VYoNGqKtqlRm7p9FnWv/OFC6p4QXT8
|
||||||
|
J1Ju2oa5iQ8iUVvznPEUz78995xMtrnpQbJCHOBvCMpYojNiOmq1d+rxZvzJrVmS
|
||||||
|
PxMtljbS1Xk60WTmGoWIFjEl8j0TARVzW3tnafEv83Ss/E4oZjo7RVVsyyAa+VQ/
|
||||||
|
6kB3HsJRdie+9FpOFU0YzyFuQb+e8mVVUSMwI42WAflDK+PD8ZjyRWVrj+WNWM0b
|
||||||
|
1Ic1Fe8BzGuDigPc6Md8i09WePyLWw+Q11x2ZCMJzKk4Nh0EPmgemusRUPXBsk0Z
|
||||||
|
ozVE/zLvqtJg+94F8q9l
|
||||||
|
-----END CERTIFICATE-----
|
||||||
28
tls.key
Normal file
28
tls.key
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsSo1M0tgSqAwE
|
||||||
|
FQ2XY8qJIdhFvJojTj2mK18gizfSEgn9whTynbKX6+AxRRlH+TQ8TQ91IYXGpZJa
|
||||||
|
AXnxpwwC1X9qjeqrKFoI9927Bgp21CzK8dI2Q7DZPTeSgAAW79dSjApwxqiw+Dy+
|
||||||
|
PP1REe94UvKg/PQezN8Zy3V4+c9F7noVgUp/xEWPsVwsH84uX2XI7HyHv4t3sMAz
|
||||||
|
qD4d/41GoJX8FZwwK5IKuIyiNVJoy2UUjcG7qXUUBUXuOcpyW0l9zwRsDtqp6mqX
|
||||||
|
j4+VCdLHKYP/X/mftLK+cwhzNvN5uWooZf78igN7rFp1n6cvmIUuQEUnnPGkwBfb
|
||||||
|
ZSFK0l7NAgMBAAECggEAAKUpL6g7X4nIvQHm/iwWoHoyGonWwtTPrDJN1deW45qJ
|
||||||
|
PAq1Dl+0WF0zQNqGEXv5F4K26D1sZVFxIYlsg8sYTBnfvvPmdNUqcMfiSRUjHhNu
|
||||||
|
gMfdIIPkd1JUxZ+2cdPoLo2KgzHe4cA4lI34LzsfXx9K8HrvGXNV8f1fjUjrR+pX
|
||||||
|
n2aCTCr+yqvF57ja9JugwOVdpWxfdJK7Km19cEDh78BTwJhmw0dUujh8eFcecxN0
|
||||||
|
m9s+HKuOs+TDhl5G2FgfmGxJgz/g5qUDPy+MulPISpQnkFNQ8lYV1FYpCxqsbm+D
|
||||||
|
L4uGNqvaUbgsl/TDuujcSnFzPNih01D6ZiHESwE/pwKBgQDSGp6RqfA7e9HTIRmW
|
||||||
|
HORupf1eE/qdIwVWVhBcmHOB6teAY5gtltEnFojOi6+nwm3yuU72pD59S+Ev08g+
|
||||||
|
fxdDAdaGR16+9Ih6KvPQNiI+2w9p0huoXIz+kZPGOYrL2d5hsKQrOnNHUEVwHQ4J
|
||||||
|
BhMrr5Sf4Xjxpv8ATgKyb39CowKBgQDR7WCAFUwvyisVrz1GDAkGzmimbLtWUsSg
|
||||||
|
dzOX0e54zDf8sC4QJdgowSIsFbfQqfkQQkUJrVA3Lk92XNfuyBo4RS9rnNv0F4eC
|
||||||
|
4CMFcBsjQ5gIgu5OHbXf1RFoc4fwabetIbb7z3xbmixQfJxgbyzySO8GZ7RwtLN+
|
||||||
|
/pVvthtfzwKBgQDHkCM3hmu5hFV7rb/o1o6fDqkHOADeSopiRCMMYH2uVArXV0IP
|
||||||
|
Y2ZMM1pEnWd99+6JEzyOhtkYF//PduCHhB3rNo62Qooa5JfROoUVKqYCf/427Cv7
|
||||||
|
EdWWY14ydSuBjvJsZeS5bq5aeUNLRz2ykoOZBhAsgHRpS86AUpi7Na5x8wKBgGi8
|
||||||
|
Dq44cfdR3ScHdAGTlZlQt8N4cgrCZplMf3Aaa+jWsoQefgzOZMcIfH0UJM41Ty6+
|
||||||
|
cWU/k8rEDx8VeSIHsZUrZ1pAOzjP2GsCWlanNNLmMV7lu/E7P3c5/WJoaYUXqWz2
|
||||||
|
ai29ueSVydAqK3atYPZMTvyaFts4PGl6qKHAcG3fAoGBALYJ7OhtEddzo3PKPZOh
|
||||||
|
uhH2vyRsLuTZCZYDGPIdxHSS0Kk307oghIZhYwKf+fx5H1Y6xtmZ59QUAg4V2Ol2
|
||||||
|
p8uoJW50skVHx/OwZkm+wQkBF+INj4akG/MaFpJ8XcwWtn8FiEMN+ljBJx7nu6dW
|
||||||
|
GxA2b5RVTQ8SBnF2TEFwjw5o
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
Reference in New Issue
Block a user