Skip to content

Commit 5b9efd8

Browse files
authored
WIP: Registry api (#115)
* Add rest endpoint to get list of available computational services
1 parent 9de5184 commit 5b9efd8

File tree

25 files changed

+442
-247
lines changed

25 files changed

+442
-247
lines changed

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ down-swarm:
3636
docker-compose -f services/docker-compose.yml -f services/docker-compose.deploy.yml down
3737
docker swarm leave -f
3838

39+
stack-up:
40+
docker swarm init
41+
POSTGRES_USER=simcore POSTGRES_PASSWORD=simcore POSTGRES_DB=simcoredb RABBITMQ_USER=simcore RABBITMQ_PASSWORD=simcore RABBITMQ_PROGRESS_CHANNEL=comp.backend.channels.progress RABBITMQ_LOG_CHANNEL=comp.backend.channels.log S3_ENDPOINT=minio:9000 S3_ACCESS_KEY=12345678 S3_SECRET_KEY=12345678 S3_BUCKET_NAME=simcore docker stack deploy -c services/docker-compose.yml -c services/docker-compose.deploy.yml osparc
42+
43+
stack-down:
44+
docker stack rm osparc
45+
docker swarm leave -f
46+
3947
pylint:
4048
# See exit codes and command line https://pylint.readthedocs.io/en/latest/user_guide/run.html#exit-codes
4149
/bin/bash -c "pylint --rcfile=.pylintrc $(PY_FILES)"

packages/s3wrapper/src/s3wrapper/s3_client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@ def list_objects(self, bucket_name, recursive=False):
130130

131131
return []
132132

133+
def list_objects_v2(self, bucket_name, recursive=False):
134+
try:
135+
return self.client.list_objects_v2(bucket_name, recursive=recursive)
136+
except ResponseError as _err:
137+
logging.exception("Could not list objects")
138+
139+
return []
140+
133141
def remove_objects(self, bucket_name, objects):
134142
try:
135143
for del_err in self.client.remove_objects(bucket_name, objects):

packages/simcore-sdk/src/simcore_sdk/config/docker.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@ def __init__(self):
77
self._registry = "masu.speag.com"
88
self._user = "z43"
99
self._pwd = "z43"
10-
10+
1111
@property
1212
def registry(self):
1313
return self._registry + "/v2"
14-
14+
15+
@property
16+
def registry_name(self):
17+
return self._registry
18+
1519
@property
1620
def user(self):
1721
return self._user
1822

1923
@property
2024
def pwd(self):
21-
return self._pwd
25+
return self._pwd

packages/simcore-sdk/src/simcore_sdk/config/s3.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,30 @@
33
"""
44
from os import environ as env
55

6-
S3_ENDPOINT = env.get("S3_ENDPOINT", "")
7-
S3_ACCESS_KEY = env.get("S3_ACCESS_KEY", "")
8-
S3_SECRET_KEY = env.get("S3_SECRET_KEY", "")
9-
S3_BUCKET_NAME = env.get("S3_BUCKET_NAME", "")
6+
S3_ENDPOINT = env.get("S3_ENDPOINT", "minio:9000")
7+
S3_ACCESS_KEY = env.get("S3_ACCESS_KEY", "12345678")
8+
S3_SECRET_KEY = env.get("S3_SECRET_KEY", "12345678")
9+
S3_BUCKET_NAME = env.get("S3_BUCKET_NAME", "simcore")
1010

1111
class Config():
1212
def __init__(self):
1313
self._endpoint = S3_ENDPOINT
1414
self._access_key = S3_ACCESS_KEY
1515
self._secret_key = S3_SECRET_KEY
1616
self._bucket_name = S3_BUCKET_NAME
17-
17+
1818
@property
1919
def endpoint(self):
2020
return self._endpoint
21-
21+
2222
@property
2323
def access_key(self):
2424
return self._access_key
25-
25+
2626
@property
2727
def secret_key(self):
2828
return self._secret_key
2929

3030
@property
3131
def bucket_name(self):
32-
return self._bucket_name
32+
return self._bucket_name

services/director/source/director.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ def stop_service():
102102
_LOGGER.exception("Failed to stop service")
103103
abort(500)
104104

105+
@APP.route('/list_repositories', methods=['GET'])
106+
def list_repositories():
107+
repos = registry_proxy.get_repo_details()
108+
109+
return json.dumps(repos)
105110

106111
if __name__ == "__main__":
107112
APP.run(host='0.0.0.0', debug=False, port=8001, threaded=True)

services/director/source/registry_proxy.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,41 @@ def get_service_sub_name(repository_name):
8686
if last_suffix_index < 0:
8787
raise Exception('Invalid service name: ' + repository_name)
8888
return list_of_suffixes[last_suffix_index]
89+
90+
def _get_repo_details(repo):
91+
#pylint: disable=too-many-nested-blocks
92+
current_repo = []
93+
if "/comp/" in repo:
94+
req_images = registry_request(repo + '/tags/list')
95+
im_data = req_images.json()
96+
tags = im_data['tags']
97+
for tag in tags:
98+
image_tags = {}
99+
label_request = registry_request(repo + '/manifests/' + tag)
100+
label_data = label_request.json()
101+
labels = json.loads(label_data["history"][0]["v1Compatibility"])["container_config"]["Labels"]
102+
if labels:
103+
for key in labels.keys():
104+
if key.startswith("io.simcore."):
105+
label_data = json.loads(labels[key])
106+
for label_key in label_data.keys():
107+
image_tags[label_key] = label_data[label_key]
108+
if image_tags:
109+
current_repo.append(image_tags)
110+
111+
return current_repo
112+
113+
def get_repo_details():
114+
request_result = registry_request('_catalog')
115+
116+
repos = request_result.json()['repositories']
117+
repositories = {}
118+
for repo in repos:
119+
details = _get_repo_details(repo)
120+
if details:
121+
repositories[repo] = details
122+
123+
result_json = json.dumps(repositories)
124+
125+
126+
return result_json

services/docker-compose.deploy.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ services:
2323
constraints:
2424
- node.platform.os == linux
2525
- node.role == manager
26+
sidecar:
27+
image: services_sidecar:latest

services/docker-compose.devel.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ services:
2222
volumes:
2323
- ./web/server:/home/scu/server
2424
- ./web/client/source-output:/home/scu/client
25-
- ../packages/simcore-sdk/src:/home/scu/packages
25+
- ../packages:/home/scu/packages
2626
depends_on:
2727
- webclient
2828
#--------------------------------------------------------------------

services/sidecar/src/sidecar/sidecar.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def _create_shared_folders(self):
5959
def _process_task_input(self, port, input_ports):
6060
port_name = port['key']
6161
port_value = port['value']
62+
_LOGGER.debug("PROCESSING %s %s", port_name, port_value)
6263
_LOGGER.debug(type(port_value))
6364
if isinstance(port_value, str) and port_value.startswith("link."):
6465
if port['type'] == 'file-url':
@@ -91,6 +92,9 @@ def _process_task_input(self, port, input_ports):
9192
for oport in other_task.output:
9293
if oport['key'] == other_output_port_id:
9394
input_ports[port_name] = oport['value']
95+
else:
96+
_LOGGER.debug('Non link data %s : %s', port_name, port_value)
97+
input_ports[port_name] = port_value
9498

9599
def _process_task_inputs(self):
96100
""" Writes input key-value pairs into a dictionary
@@ -110,16 +114,25 @@ def _process_task_inputs(self):
110114
_LOGGER.debug(port)
111115
self._process_task_input(port, input_ports)
112116

117+
_LOGGER.debug('DUMPING json')
113118
#dump json file
114119
if input_ports:
115120
file_name = os.path.join(self._executor.in_dir, 'input.json')
116121
with open(file_name, 'w') as f:
117122
json.dump(input_ports, f)
118123

124+
_LOGGER.debug('DUMPING DONE')
125+
119126
def _pull_image(self):
127+
_LOGGER.debug('PULLING IMAGE')
128+
_LOGGER.debug('reg %s user %s pwd %s', self._docker.registry, self._docker.registry_user,self._docker.registry_pwd )
129+
130+
120131
self._docker.client.login(registry=self._docker.registry,
121132
username=self._docker.registry_user, password=self._docker.registry_pwd)
122133

134+
_LOGGER.debug('img %s tag %s', self._docker.image_name, self._docker.image_tag)
135+
123136
self._docker.client.images.pull(self._docker.image_name, tag=self._docker.image_tag)
124137

125138
def _bg_job(self, task, log_file):
@@ -213,7 +226,7 @@ def _process_task_log(self):
213226

214227
def initialize(self, task):
215228
self._task = task
216-
self._docker.image_name = task.image['name']
229+
self._docker.image_name = self._docker.registry_name + "/" + task.image['name']
217230
self._docker.image_tag = task.image['tag']
218231
self._executor.in_dir = os.path.join("/", "input", task.job_id)
219232
self._executor.out_dir = os.path.join("/", "output", task.job_id)

services/sidecar/src/sidecar/sidecar_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def __init__(self):
3838
self._config = docker_config()
3939
self.client = docker.from_env(version='auto')
4040
self.registry = self._config.registry
41+
self.registry_name = self._config.registry_name
4142
self.registry_user = self._config.user
4243
self.registry_pwd = self._config.pwd
4344
self.image_name = ""

services/web/Dockerfile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ RUN apk add --no-cache \
4141

4242
ENV HOME /home/scu
4343
ENV SIMCORE_WEB_OUTDIR $HOME/client
44-
ENV PYTHONPATH "$HOME/server/src:$HOME/packages"
45-
44+
ENV PYTHONPATH "$HOME/server/src:$HOME/packages/simcore-sdk/src:$HOME/packages/s3wrapper/src"
4645

4746
WORKDIR /home/scu
4847

@@ -91,7 +90,7 @@ RUN pip3 install --no-cache-dir -r requirements/prod.txt && \
9190
rm -rf requirements
9291

9392
# 2. install 2nd party packages
94-
COPY --chown=scu:scu packages/simcore-sdk/src packages
93+
COPY --chown=scu:scu packages packages
9594

9695
# 3. install client
9796
COPY --from=services_webclient:build --chown=scu:scu /home/scu/client/build-output client

services/web/client/source/class/qxapp/components/form/Auto.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
*
4646
*/
4747

48+
/* eslint no-warning-comments: "off" */
49+
4850
qx.Class.define("qxapp.components.form.Auto", {
4951
extend : qx.ui.form.Form,
5052
include : [qx.locale.MTranslation],
@@ -366,6 +368,10 @@ qx.Class.define("qxapp.components.form.Auto", {
366368
);
367369
},
368370
__addField: function(s) {
371+
// FIXME: OM why null?
372+
if (s === null) {
373+
return;
374+
}
369375
let option = {
370376
exposable: s.exposable
371377
}; // for passing info into the form renderer
@@ -384,12 +390,21 @@ qx.Class.define("qxapp.components.form.Auto", {
384390
}
385391
s.set.value = s.defaultValue;
386392
}
393+
// FIXME: This should go away
394+
if (s.value) {
395+
if (!s.set) {
396+
s.set = {};
397+
}
398+
s.set.value = s.value;
399+
}
387400
if (!s.widget) {
388401
s.widget = {
389402
string: "text",
390403
integer: "spinner",
404+
number: "spinner",
391405
bool: "checkBox",
392-
fileUrl: "fileButton"
406+
"file-url": "fileButton",
407+
"folder-url": "fileButton"
393408
}[s.type];
394409
}
395410
let control;
@@ -405,6 +420,10 @@ qx.Class.define("qxapp.components.form.Auto", {
405420
break;
406421
case "spinner":
407422
control = new qx.ui.form.Spinner();
423+
control.set({
424+
maximum: 10000,
425+
minimum: -10000
426+
});
408427
setup = this.__setupSpinner;
409428
break;
410429
case "password":

services/web/client/source/class/qxapp/components/workbench/NodeBase.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ qx.Class.define("qxapp.components.workbench.NodeBase", {
238238
label.isInput = isInput;
239239
label.portType = portData.type;
240240

241-
label.ui = new qx.ui.basic.Label(portData.label).set({
241+
label.ui = new qx.ui.basic.Label(portData.key).set({
242242
height: 16,
243243
draggable: true,
244244
droppable: true

services/web/client/source/class/qxapp/components/workbench/Workbench.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ qx.Class.define("qxapp.components.workbench.Workbench", {
208208
var node = d["Node"];
209209
var msg = d["Message"];
210210
this.__updateLogger(node, msg);
211-
});
211+
}, this);
212212
}
213213
socket.emit("logger");
214214

@@ -220,7 +220,7 @@ qx.Class.define("qxapp.components.workbench.Workbench", {
220220
var node = d["Node"];
221221
var progress = 100*Number.parseFloat(d["Progress"]).toFixed(4);
222222
this.updateProgress(node, progress);
223-
});
223+
}, this);
224224
}
225225

226226
if (this.getCanStart()) {
@@ -811,9 +811,10 @@ qx.Class.define("qxapp.components.workbench.Workbench", {
811811
// post pipeline
812812
let currentPipeline = this.__serializeData();
813813
console.log(currentPipeline);
814-
var req = new qx.io.request.Xhr();
815-
var data = {};
816-
data["pipeline_mockup_id"] = currentPipeline;
814+
let req = new qx.io.request.Xhr();
815+
let data = {};
816+
data = currentPipeline;
817+
data["pipeline_mockup_id"] = qxapp.utils.Utils.uuidv4();
817818
req.set({
818819
url: "/start_pipeline",
819820
method: "POST",
@@ -832,7 +833,7 @@ qx.Class.define("qxapp.components.workbench.Workbench", {
832833
},
833834

834835
__onPipelinesubmitted: function(e) {
835-
var req = e.getTarget();
836+
let req = e.getTarget();
836837
console.debug("Everything went fine!!");
837838
console.debug("status : ", req.getStatus());
838839
console.debug("phase : ", req.getPhase());

0 commit comments

Comments
 (0)