Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Remote Build Plugin #269

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9fcb172
add channels packages to support remote build
kamedodji Dec 18, 2019
1d76319
add websocket support for remote build with channels
kamedodji Dec 18, 2019
fc8bf63
add remote build view mimic Sylabs Library API
kamedodji Dec 18, 2019
8c18269
add minimal doc regarding remote build support
kamedodji Dec 18, 2019
654dfbf
update doc and fix some typo...
kamedodji Dec 18, 2019
7e93573
new update doc and typos fix...
kamedodji Dec 18, 2019
fe6f7f1
replace go unmarshal with base64.b64decode
kamedodji Dec 20, 2019
518f744
suppress reference of remote build in the core app
kamedodji Dec 22, 2019
68814a0
suppress ASGI in the core app setting
kamedodji Dec 22, 2019
742acf3
move CHANNEL_LAYERS to remote_build plugin
kamedodji Dec 22, 2019
f3f7301
suppress build view from core app
kamedodji Dec 22, 2019
f08dc5e
remove endpoint v1/build from core app urls
kamedodji Dec 22, 2019
7614d5a
remove go reference in .gitignore
kamedodji Dec 22, 2019
08d172f
remove remote_build docs reference docs/_docs/client.md
kamedodji Dec 22, 2019
f689b1c
add first plugin release of remote_google
kamedodji Dec 22, 2019
1252814
transient modification of library api. Need to be fix
kamedodji Dec 22, 2019
dcd62a6
start websocket server daphne if remote_build is enabled
kamedodji Dec 22, 2019
0213c38
fix typo and delete reference to go unmarshal
kamedodji Dec 22, 2019
ae61077
remove unneed references
kamedodji Dec 22, 2019
0332e53
remove another unneed reference
kamedodji Dec 22, 2019
c86b97c
do some cleanning of unneed references
kamedodji Dec 22, 2019
38aabc9
suppress duplicated Push method and some comments
kamedodji Dec 25, 2019
d323fc7
reuse push classes and "requests" for file upload
kamedodji Dec 27, 2019
53c2b67
split Build class to Build and Push parts
kamedodji Dec 28, 2019
53bc0bb
add endpoint /v1/push to push image through API REST post
kamedodji Dec 28, 2019
9be73af
add incomplete endpoint /v1/build to build image through API REST
kamedodji Dec 28, 2019
2526290
update documentation fixing typos and take care of PR comments
kamedodji Dec 28, 2019
b110667
update documentation tittle
kamedodji Dec 28, 2019
24c2b52
update documentation code blocks with language
kamedodji Dec 28, 2019
0034198
comment out parser_classes FileUploadParser due to some issue
kamedodji Dec 28, 2019
072dee3
introduce dedicate builder container
kamedodji Jan 5, 2020
50cc60c
add pip requirements.txt
kamedodji Jan 5, 2020
2f47616
update documentation with builder info
kamedodji Jan 5, 2020
f526870
warp some lines...
kamedodji Jan 5, 2020
137c576
warp more lines...
kamedodji Jan 5, 2020
edcf1fb
continue warp lines...
kamedodji Jan 5, 2020
0543380
dedicate remote builder
kamedodji Jan 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ARG ENABLE_LDAP=false
ARG ENABLE_PAM=false
ARG ENABLE_PGP=false
ARG ENABLE_GOOGLEBUILD=false
ARG ENABLE_REMOTEBUILD=true
ARG ENABLE_GLOBUS=false
ARG ENABLE_SAML=false

Expand Down Expand Up @@ -65,6 +66,26 @@ RUN if $ENABLE_PGP; then pip install pgpdump>=1.4; fi;
RUN if $ENABLE_GOOGLEBUILD; then pip install sregistry[google-build] ; fi;
ENV SREGISTRY_GOOGLE_STORAGE_PRIVATE=true

# Install websocket requisite for remote build
RUN if $ENABLE_REMOTEBUILD; then \
apt-get update && apt-get install -y \
cryptsetup \
debootstrap \
yum ; \
pip install channels channels_redis ; \
export VERSION=1.13.4 OS=linux ARCH=amd64 && \
wget https://dl.google.com/go/go$VERSION.$OS-$ARCH.tar.gz && \
tar -C /usr/local -xzvf go$VERSION.$OS-$ARCH.tar.gz && \
rm go$VERSION.$OS-$ARCH.tar.gz; \
export VERSION=3.5.0 && \
wget https://github.com/sylabs/singularity/releases/download/v${VERSION}/singularity-${VERSION}.tar.gz && \
tar -xzf singularity-${VERSION}.tar.gz -C /tmp && \
rm singularity-${VERSION}.tar.gz; \
cd /tmp/singularity && export PATH=/usr/local/go/bin:$PATH && ./mconfig && \
make -C builddir && \
make -C builddir install; \
fi;

# Install Globus (uncomment if wanted)
RUN if $ENABLE_GLOBUS; then /bin/bash /code/scripts/globus/globus-install.sh ; fi;

Expand Down
6 changes: 4 additions & 2 deletions docs/_docs/plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ your registries' local `shub/settings/secrets.py` file.
- [SAML](saml): Authentication with SAML
- [Google Build](google-build) provides build and storage on Google Cloud.
- [Keystore](pgp) provides a standard keystore for signing containers
- [Remote Build](google-build) provides remote build library as per Sylabs API
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You didn't change the permalink here - I'm guessing you haven't written the docs? I'll need complete docs (including a link to the build server to set up first) to walk through and test your plugin.


The Dockerfile has some build arguments to build the Docker image according to the plugins software requirements. These variables are set to false by default:

Expand All @@ -34,11 +35,12 @@ ARG ENABLE_PAM=false
ARG ENABLE_GOOGLEBUILD=false
ARG ENABLE_GLOBUS=false
ARG ENABLE_SAML=false
ARG ENABLE_REMOTEBUILD=false
```

Therefore, if you want to install the requirements of all current supported plugins, you can build the image as follows:
```bash
docker build --build-arg ENABLE_LDAP=true --build-arg ENABLE_PAM=true --build-arg ENABLE_GOOGLEBUILD=true --build-arg ENABLE_GLOBUS=true --build-arg ENABLE_SAML=true -t quay.io/vanessa/sregistry .
docker build --build-arg ENABLE_LDAP=true --build-arg ENABLE_PAM=true --build-arg ENABLE_GOOGLEBUILD=true --build-arg ENABLE_GLOBUS=true --build-arg ENABLE_SAML=true --build-arg ENABLE_REMOTEBUILD=true -t quay.io/vanessa/sregistry .
```


Expand Down Expand Up @@ -67,6 +69,6 @@ RUN if $ENABLE_{PLUGIN_NAME}; then {INSTALLATION_COMMAND}; fi;
```
## Writing Documentation
Documentation for your plugin is just as important as the plugin itself! You should create a subfolder under
`docs/pages/plugins/<your-plugin>` with an appropriate README.md that is linked to in this file.
`docs/_docs/plugins/<your-plugin>` with an appropriate README.md that is linked to in this file.
Use the others as examples to guide you.

101 changes: 101 additions & 0 deletions docs/_docs/plugins/remote_build/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: "Plugin: Custom Builder and Storage"
pdf: true
toc: true
permalink: docs/plugins/remote-build
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this require a permalink, and if so, should it end in trailing slash?

---

# Plugin: Remote Build mimic sylabs API

## Configure sregistry

By default, remote build is disabled. To configure sregistry to
use Google Cloud build and Storage, in settings/config.py you can enable the plugin by
uncommenting it from the list here:

```bash
PLUGINS_ENABLED = [
# 'ldap_auth',
# 'saml_auth',
# 'globus',
# 'google_build',
'remote_build'
]
```
You will need to build the image locally with, at least, the build argument ENABLE_REMOTEBUILD set to true:

```bash
$ docker build --build-arg ENABLE_REMOTEBUILD=true -t quay.io/quay.io/vanessa/sregistry .
```

## Secrets

Next, set the following variables in `shub/settings/secrets.py`,
that you can create from `dummy_secrets.py` in the shub/settings folder.
The first two speak for themselves, your project name and path to your
Google Application Credentials.

## Singularity Remote Build

This is a first effort to provide support to `remote build`.
Freshly build image on application server (aka `worker`) is then pushed on library...
So we need [singularity client](https://sylabs.io) installed on application server.

### Motivation

Remote build provide user without local compute resource (for instance),
to build remotely and retrieved locally container image on their desktop.

It's also a way to share quickly conitainer image.

You can proceed through [googlebuild](https://singularityhub.github.io/sregistry/docs/plugins/google-build) plugin,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

google-build

but it's not everyone that have the opportunity to access google cloud, for security reason for instance...

### In the nutshell

This basic implementation of the Sylabs Library API use django
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Django

[channels](https://channels.readthedocs.io/en/latest/) Websocket Server
[Daphne](https://github.com/django/daphne/) and [ASGI](https://channels.readthedocs.io/en/latest/asgi.html)

### Requisite

This is the same than for [Singularity Push](#singularity-push)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mean Prerequisite, and that it's "the same implementation as is used for pushing a Singularity image" or something like that. This sentence doesn't make sense.


### Install

You need to build new locally image, with new argument ENABLE_REMOTEBUILD set to true:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about at the end I'll just go through this and update the language, I understand English isn't your first language, and the important thing for now is that I understand it :)

Copy link
Author

@kamedodji kamedodji Dec 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix all these typos issues. Is quiet late at France and i'll continue later....
There are no emergency and you will go a head after Christmas.

Enjoy these holiday periods and meet up later, probably next year ;-) !

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this over, and don't worry about the typos / imperfect English - if you get the main points across I should be able to help out with the English bits before it's ready for merge.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, or... in the next decade!! 💥


```
docker build --build-arg ENABLE_REMOTEBUILD=true -t quay.io/quay.io/vanessa/sregistry .
kamedodji marked this conversation as resolved.
Show resolved Hide resolved
```

### Utilisation

To build remotely image on [sregistry](https://singularityhub.github.io/sregistry):

```
singularity build --builder https://127.0.0.1 --remote <image name> <spec file>
```

Container image `<image name>` will then be generate locally and on remote library.

To generate image only remotely, use:

```
singularity build --builder https://127.0.0.1 --detached <spec file>
```

### Features

- [X] build on remote library
- [X] retrieve locally build
- [ ] implement `WYSIWYG` via web interface through popular [django-ace](https://github.com/django-ace/django-ace)
vsoch marked this conversation as resolved.
Show resolved Hide resolved

### TODO :boom:

- [ ] Automatically create collection `remote-builds`
- [ ] Re-use Django Push View in Build View
- [ ] Optimize channels consumer `BuildConsumer`
- [ ] Extend collection spacename to username
- [ ] Dedicated worker for build

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These as well.

163 changes: 163 additions & 0 deletions https/nginx.conf.wss
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
upstream websocket {
ip_hash;
server 172.17.0.6:3032 fail_timeout=0;
}

server {
listen *:80;
server_name localhost;

client_max_body_size 10024M;
client_body_buffer_size 10024M;
client_body_timeout 120;

add_header X-Clacks-Overhead "GNU Terry Pratchett";
add_header X-Clacks-Overhead "GNU Terry Pratchet";
add_header Access-Control-Allow-Origin *;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';

location /images {
alias /var/www/images;
}

location ~* \.(php|aspx|myadmin|asp)$ {
deny all;
}

location / {
include /etc/nginx/uwsgi_params.par;
uwsgi_pass uwsgi:3031;
uwsgi_max_temp_file_size 10024m;
}

location /static {
alias /var/www/static;
}

# Upload form should be submitted to this location
location /upload {

# Pass altered request body to this location
upload_pass /api/uploads/complete/;

# Store files to this directory
# The directory is hashed, subdirectories 0 1 2 3 4 5 6 7 8 9 should exist
upload_store /var/www/images/_upload 1;
upload_store_access user:rw group:rw all:rw;

# Set specified fields in request body
upload_set_form_field $upload_field_name.name "$upload_file_name";
upload_set_form_field $upload_field_name.content_type "$upload_content_type";
upload_set_form_field $upload_field_name.path "$upload_tmp_path";

# Inform backend about hash and size of a file
upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";

upload_pass_form_field "^submit$|^description$";
upload_pass_form_field "^SREGISTRY_EVENT$";
upload_pass_form_field "^collection$";
upload_pass_form_field "^name$";
upload_pass_form_field "^tag$";
upload_cleanup 400-599;

}

location /v1/build-ws/ {
proxy_pass http://websocket; # daphne (ASGI) listening on port 3032
proxy_http_version 1.1;
proxy_read_timeout 86400;
proxy_redirect off;

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}

server {

listen 443;
server_name localhost;

root html;
client_max_body_size 10024M;
client_body_buffer_size 10024M;

ssl on;
ssl_certificate /etc/ssl/certs/chained.pem;
ssl_certificate_key /etc/ssl/private/domain.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
ssl_session_cache shared:SSL:50m;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_prefer_server_ciphers on;

location /images {
alias /var/www/images;
}

location /static {
alias /var/www/static;
}

location ~* \.(php|aspx|myadmin|asp)$ {
deny all;
}

# Upload form should be submitted to this location
location /upload {

# Pass altered request body to this location
upload_pass /api/uploads/complete/;

# Store files to this directory
# The directory is hashed, subdirectories 0 1 2 3 4 5 6 7 8 9 should exist
upload_store /var/www/images/_upload 1;
upload_store_access user:rw group:rw all:rw;

# Set specified fields in request body
upload_set_form_field $upload_field_name.name "$upload_file_name";
upload_set_form_field $upload_field_name.content_type "$upload_content_type";
upload_set_form_field $upload_field_name.path "$upload_tmp_path";

# Inform backend about hash and size of a file
upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";

upload_pass_form_field "^submit$|^description$";
upload_pass_form_field "^SREGISTRY_EVENT$";
upload_pass_form_field "^collection$";
upload_pass_form_field "^name$";
upload_pass_form_field "^tag$";
upload_cleanup 400-599;

}

location / {
include /etc/nginx/uwsgi_params.par;
uwsgi_pass uwsgi:3031;
uwsgi_max_temp_file_size 10024m;
}

location /v1/build-ws/ {
proxy_pass http://websocket; # daphne (ASGI) listening on port 3032
proxy_http_version 1.1;
proxy_read_timeout 86400;
proxy_redirect off;

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}

Loading