Skip to content

Commit

Permalink
Merge pull request #243 from SelfhostedPro/develop
Browse files Browse the repository at this point in the history
Alpha 6 (v0.0.6-alpha)
  • Loading branch information
SelfhostedPro authored Feb 19, 2021
2 parents b6ff614 + 9288456 commit 4fad812
Show file tree
Hide file tree
Showing 55 changed files with 3,503 additions and 2,294 deletions.
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Build Vue
FROM node:14.5.0-alpine as build-stage

ARG VUE_APP_VERSION
ENV VUE_APP_VERSION=${VUE_APP_VERSION}

WORKDIR /app
COPY ./frontend/package*.json ./
RUN npm install
Expand All @@ -26,14 +29,16 @@ RUN \
make \
python3-dev \
libffi-dev \
ruby-dev &&\
ruby-dev \
postgresql-dev &&\
echo "**** install packages ****" && \
apk add --no-cache \
python3 \
py3-pip \
nginx &&\
gem install sass &&\
echo "**** Installing Python Modules ****" && \
pip3 install wheel &&\
pip3 install -r requirements.txt &&\
echo "**** Cleaning Up ****" &&\
apk del --purge \
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ Check out the getting started guide if this is the first time you've used Yacht:
* Template Framework
* Easy Template Updating
* Centralized settings for volume management and similar QOL functionality.
* Docker-Compose Compatibility
* Advanced Container Management (Edit/Modify)


## Planned Features:
* Advanced Container Management (Edit/Modify)
* Container Monitoring
* Docker-Compose Compatibility
* Easy access to container interfaces
* User Management
* Scheduled Jobs

*If you want something that's not planned please open a feature request issue and we'll see about getting it added.*

Expand Down
5 changes: 3 additions & 2 deletions backend/alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@

from api.db import models
from api.settings import Settings
from api.auth import Base

print("--- MODELS ---")
print(models)
# Combine metadata from auth and containers/templates
combined_meta_data = MetaData()
for declarative_base in [models.Base, Base]:
for declarative_base in [models.Base]:
for (table_name, table) in declarative_base.metadata.tables.items():
combined_meta_data._add_table(table_name, table.schema, table)

Expand Down
139 changes: 122 additions & 17 deletions backend/api/actions/apps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from fastapi import HTTPException
from fastapi import HTTPException, BackgroundTasks
from ..db import models, schemas
from ..utils import *
from ..utils import check_updates as _update_check
Expand All @@ -11,6 +11,10 @@
import subprocess
import docker

"""
Returns all running apps in a list
"""


def get_running_apps():
apps_list = []
Expand All @@ -26,6 +30,14 @@ def get_running_apps():
return apps_list


"""
Checks repo digest for app and compares it to image
digest to see if there's an update available.
TODO: This has issues if there's more than one repo digest
"""


def check_app_update(app_name):
dclient = docker.from_env()
try:
Expand All @@ -44,9 +56,18 @@ def check_app_update(app_name):
return app.attrs


"""
Gets all apps in a list and add some easy access to
properties that aren't in the app attributes
"""


def get_apps():
apps_list = []
dclient = docker.from_env()
try:
dclient = docker.from_env()
except docker.errors.DockerException as exc:
raise HTTPException(status_code=500, detail=exc.args)
try:
apps = dclient.containers.list(all=True)
except Exception as exc:
Expand All @@ -64,6 +85,13 @@ def get_apps():
return apps_list


"""
Get a single app by the container name and some easy
access to properties that aren't in the app
attributes
"""


def get_app(app_name):
dclient = docker.from_env()
try:
Expand All @@ -81,6 +109,11 @@ def get_app(app_name):
return attrs


"""
Get processes running in an app.
"""


def get_app_processes(app_name):
dclient = docker.from_env()
app = dclient.containers.get(app_name)
Expand All @@ -93,6 +126,12 @@ def get_app_processes(app_name):
return None


"""
Get app logs (this isn't in use as logs are served
via a websocket in routers so they're realtime)
"""


def get_app_logs(app_name):
dclient = docker.from_env()
app = dclient.containers.get(app_name)
Expand All @@ -102,6 +141,12 @@ def get_app_logs(app_name):
return None


"""
Deploy a new app. Format is available in
../db/schemas/apps.py
"""


def deploy_app(template: schemas.DeployForm):
try:
launch = launch_app(
Expand All @@ -118,6 +163,8 @@ def deploy_app(template: schemas.DeployForm):
conv_labels2data(template.labels),
conv_sysctls2data(template.sysctls),
conv_caps2data(template.cap_add),
edit=template.edit or False,
id=template.id or None
)
except HTTPException as exc:
raise HTTPException(status_code=exc.status_code, detail=exc.detail)
Expand All @@ -130,9 +177,16 @@ def deploy_app(template: schemas.DeployForm):
return schemas.DeployLogs(logs=launch.logs())


"""
Merge utility used for combining portlabels and
labels into a single variable
"""


def Merge(dict1, dict2):
if dict1 and dict2:
return dict2.update(dict1)
dict2.update(dict1)
return dict2
elif dict1:
return dict1
elif dict2:
Expand All @@ -141,6 +195,14 @@ def Merge(dict1, dict2):
return None


"""
This function actually runs the docker run command.
It also checks if edit is set to true so it can
remove the container you're editing before deploying
a new one.
"""


def launch_app(
name,
image,
Expand All @@ -155,8 +217,22 @@ def launch_app(
labels,
sysctls,
caps,
edit,
id
):
dclient = docker.from_env()
if edit == True:
try:
dclient.containers.get(id)
try:
running_app = dclient.containers.get(id)
running_app.remove(force=True)
except Exception as e:
raise e
except Exception as e:
# User probably changed the name so it doesn't conflict. If this is the case we'll just spin up a second container.
pass

combined_labels = Merge(portlabels, labels)
try:
lauch = dclient.containers.run(
Expand Down Expand Up @@ -191,6 +267,11 @@ def launch_app(
return lauch


"""
Runs an app action (ie. docker stop, docker start, etc.)
"""


def app_action(app_name, action):
err = None
dclient = docker.from_env()
Expand All @@ -214,6 +295,12 @@ def app_action(app_name, action):
return apps_list


"""
Spins up a watchtower container that uses the --run-once
and --cleanup flags and targets a container by name
"""


def app_update(app_name):
dclient = docker.from_env()
try:
Expand Down Expand Up @@ -252,7 +339,14 @@ def app_update(app_name):
return get_apps()


def update_self():
"""
Checks for current docker id (the one yacht is running
in) and then launches the next function in a
background task.
"""


def _update_self(background_tasks):
dclient = docker.from_env()
bash_command = "head -1 /proc/self/cgroup|cut -d/ -f3"
yacht_id = (
Expand All @@ -268,23 +362,36 @@ def update_self():
detail="Unable to get Yacht container ID",
)
else:
raise HTTPException(
status_code=exc.response.status_code, detail=exc.explanation
)
status_code = 500
detail = exc.args[0]
raise HTTPException(status_code=status_code, detail=detail)
background_tasks.add_task(update_self_in_background, yacht)
return {"result": "successful"}


"""
Spins up a watchtower instance with --cleanup and
--run-once pointed at the current ID of yacht.
"""


def update_self_in_background(yacht):
dclient = docker.from_env()
volumes = {"/var/run/docker.sock": {"bind": "/var/run/docker.sock", "mode": "rw"}}
print("**** Updating " + yacht.name + "****")
updater = dclient.containers.run(
dclient.containers.run(
image="containrrr/watchtower:latest",
command="--cleanup --run-once " + yacht.name,
remove=True,
detach=True,
volumes=volumes,
)
result = updater
print(result)
time.sleep(1)
return result


"""
Checks current docker id and compares the repo digest
to the local digest to see if there's an updata available.
"""


def check_self_update():
Expand All @@ -297,18 +404,16 @@ def check_self_update():
yacht = dclient.containers.get(yacht_id)
except Exception as exc:
print(exc)
if hasattr(exc, 'response') and exc.response.status_code == 404:
if hasattr(exc, "response") and exc.response.status_code == 404:
raise HTTPException(
status_code=exc.response.status_code,
detail="Unable to get Yacht container ID",
)
elif hasattr(exc, 'response'):
elif hasattr(exc, "response"):
raise HTTPException(
status_code=exc.response.status_code, detail=exc.explanation
)
else:
raise HTTPException(
status_code=400, detail=exc.args
)
raise HTTPException(status_code=400, detail=exc.args)

return _update_check(yacht.image.tags[0])
Loading

0 comments on commit 4fad812

Please sign in to comment.