mirror of
https://github.com/Steffo99/sophon.git
synced 2024-12-22 06:44:21 +00:00
💥 Things
This commit is contained in:
parent
0555c9a97e
commit
d85f57e04a
10 changed files with 57 additions and 34 deletions
|
@ -39,7 +39,6 @@ class NotebookAdmin(SophonAdmin):
|
||||||
"fields": (
|
"fields": (
|
||||||
"container_image",
|
"container_image",
|
||||||
"container_id",
|
"container_id",
|
||||||
"internet_access",
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.2.7 on 2021-10-19 19:46
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('notebooks', '0011_auto_20211019_1745'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='notebook',
|
||||||
|
name='internal_url',
|
||||||
|
field=models.CharField(blank=True,
|
||||||
|
help_text='The URL reachable from the proxy where the container is available. Can be null if the notebook is not running.',
|
||||||
|
max_length=512, null=True, verbose_name='Internal URL'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -114,10 +114,11 @@ class Notebook(SophonGroupModel):
|
||||||
blank=True, null=True,
|
blank=True, null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
internal_url = models.IntegerField(
|
internal_url = models.CharField(
|
||||||
"Internal URL",
|
"Internal URL",
|
||||||
help_text="The URL reachable from the proxy where the container is available. Can be null if the notebook is not running.",
|
help_text="The URL reachable from the proxy where the container is available. Can be null if the notebook is not running.",
|
||||||
blank=True, null=True,
|
blank=True, null=True,
|
||||||
|
max_length=512,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_group(self) -> ResearchGroup:
|
def get_group(self) -> ResearchGroup:
|
||||||
|
@ -131,7 +132,6 @@ class Notebook(SophonGroupModel):
|
||||||
"name",
|
"name",
|
||||||
"locked_by",
|
"locked_by",
|
||||||
"container_image",
|
"container_image",
|
||||||
"internet_access",
|
|
||||||
"is_running",
|
"is_running",
|
||||||
"lab_url",
|
"lab_url",
|
||||||
"legacy_notebook_url",
|
"legacy_notebook_url",
|
||||||
|
@ -174,28 +174,28 @@ class Notebook(SophonGroupModel):
|
||||||
"""
|
"""
|
||||||
:return: The name given to the container associated with this :class:`Notebook`.
|
:return: The name given to the container associated with this :class:`Notebook`.
|
||||||
"""
|
"""
|
||||||
return f"{settings.CONTAINER_PREFIX}-{self.slug}"
|
return f"{settings.DOCKER_CONTAINER_PREFIX}-{self.slug}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volume_name(self) -> str:
|
def volume_name(self) -> str:
|
||||||
"""
|
"""
|
||||||
:return: The name given to the volume associated with this :class:`Notebook`.
|
:return: The name given to the volume associated with this :class:`Notebook`.
|
||||||
"""
|
"""
|
||||||
return f"{settings.VOLUME_PREFIX}-{self.slug}"
|
return f"{settings.DOCKER_VOLUME_PREFIX}-{self.slug}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def network_name(self) -> str:
|
def network_name(self) -> str:
|
||||||
"""
|
"""
|
||||||
:return: The name given to the network associated with this :class:`Notebook`.
|
:return: The name given to the network associated with this :class:`Notebook`.
|
||||||
"""
|
"""
|
||||||
return f"{settings.NETWORK_PREFIX}-{self.slug}"
|
return f"{settings.DOCKER_NETWORK_PREFIX}-{self.slug}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def external_domain(self) -> str:
|
def external_domain(self) -> str:
|
||||||
"""
|
"""
|
||||||
:return: The domain name where this :class:`Notebook` will be accessible on the Internet after its container is started.
|
:return: The domain name where this :class:`Notebook` will be accessible on the Internet after its container is started.
|
||||||
"""
|
"""
|
||||||
return f"{self.slug}.{settings.PROXY_DOMAIN}"
|
return f"{self.slug}.{settings.PROXY_BASE_DOMAIN}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lab_url(self) -> t.Optional[str]:
|
def lab_url(self) -> t.Optional[str]:
|
||||||
|
@ -322,7 +322,10 @@ class Notebook(SophonGroupModel):
|
||||||
proxy = get_proxy_container()
|
proxy = get_proxy_container()
|
||||||
|
|
||||||
self.log.debug("Disconnecting proxy container from the network...")
|
self.log.debug("Disconnecting proxy container from the network...")
|
||||||
|
try:
|
||||||
network.disconnect(proxy)
|
network.disconnect(proxy)
|
||||||
|
except docker.errors.APIError:
|
||||||
|
self.log.debug("Container was already disconnected.")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.log.debug("Unassigning port...")
|
self.log.debug("Unassigning port...")
|
||||||
|
@ -485,7 +488,7 @@ class Notebook(SophonGroupModel):
|
||||||
name=self.container_name,
|
name=self.container_name,
|
||||||
ports={
|
ports={
|
||||||
"8888/tcp": (f"127.0.0.1", f"{self.port}/tcp")
|
"8888/tcp": (f"127.0.0.1", f"{self.port}/tcp")
|
||||||
},
|
} if self.port else {},
|
||||||
environment={
|
environment={
|
||||||
"JUPYTER_ENABLE_LAB": "yes",
|
"JUPYTER_ENABLE_LAB": "yes",
|
||||||
"RESTARTABLE": "yes",
|
"RESTARTABLE": "yes",
|
||||||
|
@ -498,7 +501,7 @@ class Notebook(SophonGroupModel):
|
||||||
"mode": "rw",
|
"mode": "rw",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
network=network,
|
network=network.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.log.debug("Storing container_id in the SQL database...")
|
self.log.debug("Storing container_id in the SQL database...")
|
||||||
|
|
|
@ -3,7 +3,8 @@ version: "3.9"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
proxy-data:
|
proxy-data:
|
||||||
static-data:
|
django-static:
|
||||||
|
react-static:
|
||||||
db-data:
|
db-data:
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,9 +44,9 @@ services:
|
||||||
# TODO: Configure your proxy details!
|
# TODO: Configure your proxy details!
|
||||||
- DJANGO_PROXY_BASE_DOMAIN=dev.sophon.steffo.eu
|
- DJANGO_PROXY_BASE_DOMAIN=dev.sophon.steffo.eu
|
||||||
- DJANGO_PROXY_PROTOCOL=http
|
- DJANGO_PROXY_PROTOCOL=http
|
||||||
- DJANGO_PROXY_CONTAINER_NAME=proxy
|
- DJANGO_PROXY_CONTAINER_NAME=sophon2-proxy-1 # The correct name probably is $DIRECTORYNAME-proxy-1
|
||||||
# TODO: Configure your static url!
|
# TODO: Configure your static url!
|
||||||
- DJANGO_STATIC_URL=http://static.dev.sophon.steffo.eu/@django-static/
|
- DJANGO_STATIC_URL=http://static.dev.sophon.steffo.eu/django-static/
|
||||||
# TODO: Set your language!
|
# TODO: Set your language!
|
||||||
- DJANGO_LANGUAGE_CODE=en-us
|
- DJANGO_LANGUAGE_CODE=en-us
|
||||||
# TODO: Set your timezone!
|
# TODO: Set your timezone!
|
||||||
|
@ -69,7 +70,7 @@ services:
|
||||||
- DJANGO_DOCKER_CERT_PATH=
|
- DJANGO_DOCKER_CERT_PATH=
|
||||||
volumes:
|
volumes:
|
||||||
- proxy-data:/run/sophon/proxy
|
- proxy-data:/run/sophon/proxy
|
||||||
- static-data:/run/sophon/static
|
- django-static:/run/sophon/static
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
|
@ -88,7 +89,8 @@ services:
|
||||||
- SOPHON_FRONTEND_NAME=frontend:5000
|
- SOPHON_FRONTEND_NAME=frontend:5000
|
||||||
volumes:
|
volumes:
|
||||||
- proxy-data:/run/sophon/proxy
|
- proxy-data:/run/sophon/proxy
|
||||||
- static-data:/usr/local/apache2/htdocs/django-static
|
- django-static:/usr/local/apache2/htdocs/django-static
|
||||||
|
- react-static:/usr/local/apache2/htdocs/react-static
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
- frontend
|
- frontend
|
||||||
|
|
|
@ -15,4 +15,5 @@ RUN yarn install
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Start the serve server
|
# Start the serve server
|
||||||
ENTRYPOINT ["yarn", "run", "serve"]
|
ENTRYPOINT ["yarn", "run"]
|
||||||
|
CMD ["serve"]
|
|
@ -5,6 +5,7 @@
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/src/components/legacy" />
|
<excludeFolder url="file://$MODULE_DIR$/src/components/legacy" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Poetry (frontend)" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Poetry (frontend)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
|
|
@ -3,12 +3,13 @@ import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import {Box, Heading, Idiomatic} from "@steffo/bluelib-react"
|
import {Box, Heading, Idiomatic} from "@steffo/bluelib-react"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import ReactMarkdown from "react-markdown"
|
import ReactMarkdown from "react-markdown"
|
||||||
|
import {Empty} from "./Empty"
|
||||||
|
|
||||||
|
|
||||||
export interface DescriptionBoxProps {
|
export interface DescriptionBoxProps {
|
||||||
icon: IconDefinition,
|
icon: IconDefinition,
|
||||||
name: string,
|
name: string,
|
||||||
description: string,
|
description?: string | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,9 +20,16 @@ export function DescriptionBox({icon, name, description}: DescriptionBoxProps):
|
||||||
<Heading level={3}>
|
<Heading level={3}>
|
||||||
<FontAwesomeIcon icon={icon}/> About <Idiomatic>{name}</Idiomatic>
|
<FontAwesomeIcon icon={icon}/> About <Idiomatic>{name}</Idiomatic>
|
||||||
</Heading>
|
</Heading>
|
||||||
|
{
|
||||||
|
description ?
|
||||||
<ReactMarkdown>
|
<ReactMarkdown>
|
||||||
{description}
|
{description}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
|
:
|
||||||
|
<Empty>
|
||||||
|
This resource has no about text.
|
||||||
|
</Empty>
|
||||||
|
}
|
||||||
</Box>
|
</Box>
|
||||||
),
|
),
|
||||||
[icon, name, description],
|
[icon, name, description],
|
||||||
|
|
|
@ -16,10 +16,6 @@ export function InstanceDescriptionBox(): JSX.Element | null {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!instance.state.details.description) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DescriptionBox
|
<DescriptionBox
|
||||||
icon={faUniversity}
|
icon={faUniversity}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {DjangoResource, DjangoSlug} from "./DjangoTypes";
|
import {DjangoResource, DjangoSlug} from "./DjangoTypes"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,9 +64,8 @@ export interface SophonNotebook extends DjangoResource {
|
||||||
locked_by: number,
|
locked_by: number,
|
||||||
slug: DjangoSlug,
|
slug: DjangoSlug,
|
||||||
legacy_notebook_url: string | null,
|
legacy_notebook_url: string | null,
|
||||||
jupyter_token: string,
|
jupyter_token?: string,
|
||||||
is_running: boolean,
|
is_running: boolean,
|
||||||
internet_access: true,
|
|
||||||
container_image: string,
|
container_image: string,
|
||||||
project: DjangoSlug,
|
project: DjangoSlug,
|
||||||
name: string,
|
name: string,
|
||||||
|
|
|
@ -561,12 +561,13 @@ RewriteEngine on
|
||||||
# Preserve host
|
# Preserve host
|
||||||
ProxyPreserveHost on
|
ProxyPreserveHost on
|
||||||
|
|
||||||
|
|
||||||
# Proxy regular requests to the frontend
|
# Proxy regular requests to the frontend
|
||||||
# sophon.steffo.eu → frontend
|
# sophon.steffo.eu → frontend
|
||||||
RewriteCond "%{ENV:matched}" "! -eq 1" [NC] # If the url hasn't been matched by the previous rules
|
RewriteCond "%{ENV:matched}" "! -eq 1" [NC] # If the url hasn't been matched by the previous rules
|
||||||
RewriteCond "%{ENV:APACHE_PROXY_BASE_DOMAIN} %{HTTP_HOST}" "^([^ ]+) \1$" [NC] # If ENV:APACHE_PROXY_BASE_DOMAIN equals HTTP_HOST
|
RewriteCond "%{ENV:APACHE_PROXY_BASE_DOMAIN} %{HTTP_HOST}" "^([^ ]+) \1$" [NC] # If ENV:APACHE_PROXY_BASE_DOMAIN equals HTTP_HOST
|
||||||
RewriteCond "%{ENV:SOPHON_FRONTEND_NAME}" "^(.+)$" [NC] # Capture ENV:SOPHON_FRONTEND_NAME for substitution in the rewriterule
|
RewriteCond "%{ENV:SOPHON_FRONTEND_NAME}" "^(.+)$" [NC] # Capture ENV:SOPHON_FRONTEND_NAME for substitution in the rewriterule
|
||||||
RewriteRule "/(.*)" "http://%1/$1" [P,L,E=matched:1] # Rewrite and set the matched flag
|
RewriteRule "/(.*)" "http://%1/$1" [P,L,E=matched:1] # Rewrite as a SPA and set the matched flag
|
||||||
|
|
||||||
# Proxy api requests to the backend
|
# Proxy api requests to the backend
|
||||||
# api.sophon.steffo.eu → backend
|
# api.sophon.steffo.eu → backend
|
||||||
|
@ -575,12 +576,6 @@ RewriteCond "api.%{ENV:APACHE_PROXY_BASE_DOMAIN} %{HTTP_HOST}" "^([^ ]+) \1$" [N
|
||||||
RewriteCond "%{ENV:SOPHON_BACKEND_NAME}" "^(.+)$" [NC] # Capture ENV:SOPHON_BACKEND_NAME for substitution in the rewriterule
|
RewriteCond "%{ENV:SOPHON_BACKEND_NAME}" "^(.+)$" [NC] # Capture ENV:SOPHON_BACKEND_NAME for substitution in the rewriterule
|
||||||
RewriteRule "/(.*)" "http://%1/$1" [P,L,E=matched:1] # Rewrite and set the matched flag
|
RewriteRule "/(.*)" "http://%1/$1" [P,L,E=matched:1] # Rewrite and set the matched flag
|
||||||
|
|
||||||
# Proxy static requests to the static files
|
|
||||||
# static.sophon.steffo.eu → static
|
|
||||||
RewriteCond "%{ENV:matched}" "! -eq 1" [NC] # If the url hasn't been matched by the previous rules
|
|
||||||
RewriteCond "static.%{ENV:APACHE_PROXY_BASE_DOMAIN} %{HTTP_HOST}" "^([^ ]+) \1$" [NC] # If static. prefixed to ENV:APACHE_PROXY_BASE_DOMAIN equals HTTP_HOST
|
|
||||||
RewriteRule "/@django-static/(.*)" "/django-static/$1" [P,L,E=matched:1] # Rewrite and set the matched flag
|
|
||||||
|
|
||||||
# Create a map between the proxy file generated by Sophon and Apache
|
# Create a map between the proxy file generated by Sophon and Apache
|
||||||
RewriteMap "sophonproxy" "dbm=gdbm:/run/sophon/proxy/proxy.dbm"
|
RewriteMap "sophonproxy" "dbm=gdbm:/run/sophon/proxy/proxy.dbm"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue