Compare commits

..

45 Commits

Author SHA1 Message Date
Andrey Melnikov
cbecaf6fa1 Merge pull request #546 from onepanelio/dev
feat: update master with latest release changes 0.12.0
2020-08-25 16:33:45 -07:00
Rush Tehrani
de7f060c81 Merge pull request #537 from onepanelio/feat/core.415-jupyter.lab.workspace
feat: Added migration for new Jupyterlab Workspace, 1.0.1
2020-08-25 16:30:07 -07:00
Rush Tehrani
c723a3270f Remove TensorBoard, it can be run in the notebook 2020-08-25 16:29:38 -07:00
Rush Tehrani
24bb7cb0a5 Merge pull request #545 from onepanelio/feat/cvat.update
fix: cvat to 0.12.0_cvat.1.0.0
2020-08-25 15:56:56 -07:00
Andrey Melnikov
a51d4b662e update: documentation 2020-08-25 15:49:04 -07:00
Andrey Melnikov
6e72b550b1 update: cvat to 0.12.0_cvat.1.0.0 2020-08-25 15:47:41 -07:00
Aleksandr Melnikov
1f95b87699 Using a fixed image. 2020-08-25 15:36:09 -07:00
Rush Tehrani
8258c5f19b Merge pull request #544 from onepanelio/fix/fix.regression
fix: Fixing code that was removed during a merge and caused a regression.
2020-08-25 15:19:10 -07:00
Aleksandr Melnikov
e61341c50a Fixing merge removed code. 2020-08-25 15:13:02 -07:00
Rush Tehrani
8c0a763404 Merge pull request #542 from onepanelio/fix/update.migrations.to.support.more.than.s3
fix: Adding support for different bucket storages in the db migrations
2020-08-25 14:45:20 -07:00
Aleksandr Melnikov
76bc226a2e Merge branch 'dev' into fix/update.migrations.to.support.more.than.s3 2020-08-25 14:25:06 -07:00
Andrey Melnikov
e1dd4b8ed1 Merge pull request #543 from onepanelio/fix/migrations.namespaces
fix: issue where migrations crashed with multiple namespaces
2020-08-25 12:50:00 -07:00
Aleksandr Melnikov
1e3b9ca278 Merge branch 'dev' into feat/core.415-jupyter.lab.workspace 2020-08-25 12:46:42 -07:00
Andrey Melnikov
cde5b54830 fix: issue where workspace templates were changed during update, resulting in crash if more than one namespace attempted updates. 2020-08-25 12:45:11 -07:00
Aleksandr Melnikov
d2adb109e1 Adding comment for function. 2020-08-25 11:32:33 -07:00
Aleksandr Melnikov
6eac7f2c74 Adding support for different bucket storages.
- Updating various migrations
- Adding helper function
2020-08-25 10:55:43 -07:00
Andrey Melnikov
9e4eb59cec Merge pull request #538 from onepanelio/feat/update.migrations
feat: updated migrations for cvat, tf od training, maskrcnn
2020-08-24 11:43:10 -07:00
Andrey Melnikov
0ccd871e54 update: templates 2020-08-24 11:08:20 -07:00
Andrey Melnikov
4bb205257a fix: tf-object detection training template 2020-08-24 10:46:52 -07:00
Andrey Melnikov
bbbf1c0d6a chore: docs for latest migrations 2020-08-24 10:29:26 -07:00
Andrey Melnikov
f9b23a7d2a feat: updated migrations for cvat, tf object detection training, maskrcnn 2020-08-24 10:24:56 -07:00
Rush Tehrani
53c88c8390 Fix postExecutionWorkflow 2020-08-24 10:22:24 -07:00
Aleksandr Melnikov
b7e4281eeb Adding migration for new jupyterlab workspace. 2020-08-21 16:46:19 -07:00
Andrey Melnikov
f533ce01b3 Merge pull request #527 from onepanelio/fix/permissions.messages
feat: permissions issues are now more detailed in API responses
2020-08-21 12:54:03 -07:00
Andrey Melnikov
abba7b5476 Merge pull request #530 from onepanelio/fix/migration.template
fix: issue where migration crashed
2020-08-20 13:21:07 -07:00
Andrey Melnikov
96861e19d3 fix: issue where migration crashed because a workflow template did not yet exist 2020-08-20 12:56:52 -07:00
Andrey Melnikov
93d1b4a2c0 update: permissions issues are now more detailed 2020-08-19 11:00:40 -07:00
Andrey Melnikov
0ffa3aee32 Merge pull request #383 from onepanelio/dev
fix: migration issue (into master)
2020-06-29 22:21:52 -07:00
Andrey Melnikov
35982bf85a Merge pull request #381 from onepanelio/dev
feat: v0.11.0
2020-06-29 11:08:18 -07:00
Rush Tehrani
ecadd189a2 Create issue_label_bot.yaml 2020-06-07 12:33:05 -07:00
Rush Tehrani
b68de30418 Merge pull request #321 from onepanelio/dev
chore: dev > master  (v0.10.0)
2020-06-05 13:06:29 -07:00
Rush Tehrani
dedc295441 Update LICENSE 2020-06-04 19:50:39 -07:00
Rush Tehrani
2108691f68 Update PULL_REQUEST_TEMPLATE.md 2020-06-04 18:26:20 -07:00
Rush Tehrani
0262a9ec90 Update PULL_REQUEST_TEMPLATE.md 2020-06-04 16:01:17 -07:00
Rush Tehrani
c6c8e80516 Delete badge.yaml 2020-06-04 15:54:12 -07:00
Rush Tehrani
9381dd0a85 Update badge.yaml 2020-06-04 14:52:37 -07:00
Rush Tehrani
b6f7118a43 Create badge.yaml 2020-06-04 12:56:27 -07:00
Rush Tehrani
f7b941f8a0 Update PULL_REQUEST_TEMPLATE.md 2020-06-04 12:52:45 -07:00
Rush Tehrani
e00a54c24e Create semantic.yml 2020-06-03 16:04:19 -07:00
rushtehrani
8d29cd0c5c remove extra space 2020-06-02 14:32:34 -07:00
rushtehrani
dafaadd80a fix kind 2020-06-02 14:26:10 -07:00
rushtehrani
4f036468b0 add PR template 2020-06-02 14:14:45 -07:00
Rush Tehrani
8df966fcee Create PULL_REQUEST_TEMPLATE.md 2020-06-02 14:10:45 -07:00
Rush Tehrani
cfd9bc6f43 Add badge 2020-05-25 13:38:05 -07:00
Rush Tehrani
3ee8497cac Merge pull request #258 from onepanelio/develop
dev > master
2020-05-25 13:37:08 -07:00
19 changed files with 1212 additions and 34 deletions

16
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,16 @@
<!-- Thanks for sending a pull request! Here are some tips for you:
1. Please read our contributor guidelines: https://docs.onepanel.ai/docs/getting-started/contributing
2. Prefix the title of this PR with `feat:`, `fix:`, `docs:` or `chore:`, example: `feat: added great feature`
3. If this PR is a feature or enhancement, then create an issue (https://github.com/onepanelio/core/issues) first.
-->
**What this PR does**:
**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes onepanelio/core#<issue-number>`
-->
Fixes onepanelio/core#
**Special notes for your reviewer**:

4
.github/issue_label_bot.yaml vendored Normal file
View File

@@ -0,0 +1,4 @@
label-alias:
bug: 'kind/bug'
feature_request: 'kind/enhancement'
question: 'kind/question'

1
.github/semantic.yml vendored Normal file
View File

@@ -0,0 +1 @@
titleOnly: true

View File

@@ -1,3 +1,5 @@
Copyright 2020 Onepanel, Inc. All rights reserved.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

View File

@@ -1,3 +1,5 @@
![Build and publish to Docker Hub](https://github.com/onepanelio/core/workflows/Build%20and%20publish%20to%20Docker%20Hub/badge.svg)
# Onepanel
Welcome to Onepanel! This is the main repository for the API. It is also where you can submit bugs and enhancement requests.
@@ -10,4 +12,4 @@ See our [Quick start guide](https://docs.onepanel.ai/docs/getting-started/quicks
See our [Contribution guide](https://docs.onepanel.ai/docs/getting-started/contributing) to get started.
## Acknowledgments
Onepanel uses the excellent [Argo](https://github.com/argoproj/argo) project under the hood to orchestrate workflows.
Onepanel uses the excellent [Argo](https://github.com/argoproj/argo) project under the hood to orchestrate workflows.

View File

@@ -15,7 +15,7 @@ service AuthService {
rpc IsAuthorized(IsAuthorizedRequest) returns (IsAuthorizedResponse) {
option (google.api.http) = {
post: "/apis/v1beta1/auth",
post: "/apis/v1beta1/auth"
body: "isAuthorized"
};
}

View File

@@ -152,13 +152,14 @@ func Up20200626113635(tx *sql.Tx) error {
if err != nil {
return err
}
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate2,
}
for _, namespace := range namespaces {
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate2,
}
if _, err := client.UpdateWorkspaceTemplate(namespace.Name, workspaceTemplate); err != nil {
return err
}

View File

@@ -154,13 +154,13 @@ func Up20200704151301(tx *sql.Tx) error {
if err != nil {
return err
}
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate3,
}
for _, namespace := range namespaces {
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate3,
}
if _, err := client.UpdateWorkspaceTemplate(namespace.Name, workspaceTemplate); err != nil {
return err
}

View File

@@ -172,11 +172,6 @@ func Up20200724220450(tx *sql.Tx) error {
if err != nil {
return err
}
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate4,
}
for _, namespace := range namespaces {
artifactRepositoryType := "s3"
@@ -187,6 +182,12 @@ func Up20200724220450(tx *sql.Tx) error {
if nsConfig.ArtifactRepository.GCS != nil {
artifactRepositoryType = "gcs"
}
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate4,
}
workspaceTemplate.Manifest = strings.NewReplacer(
"{{.ArtifactRepositoryType}}", artifactRepositoryType).Replace(workspaceTemplate.Manifest)
if _, err := client.UpdateWorkspaceTemplate(namespace.Name, workspaceTemplate); err != nil {

View File

@@ -144,7 +144,7 @@ templates:
artifacts:
- name: data
path: /mnt/data/datasets/
s3:
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.sys-annotation-path}}'
- git:
repo: '{{workflow.parameters.source}}'
@@ -157,7 +157,7 @@ templates:
- name: model
optional: true
path: /mnt/output
s3:
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.sys-output-path}}'
# Uncomment the lines below if you want to send Slack notifications
#- container:
@@ -348,12 +348,12 @@ templates:
artifacts:
- name: data
path: /mnt/data/datasets/
s3:
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.sys-annotation-path}}'
- name: models
path: /mnt/data/models/
optional: true
s3:
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.sys-finetune-checkpoint}}'
- git:
repo: '{{workflow.parameters.source}}'
@@ -371,7 +371,7 @@ templates:
- name: model
optional: true
path: /mnt/output
s3:
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.sys-output-path}}'
# Uncomment the lines below if you want to send Slack notifications
#- container:
@@ -469,13 +469,16 @@ func Up20200812104328(tx *sql.Tx) error {
log.Printf("Skipping creating template '%v'. It already exists in namespace '%v'", workflowTemplate.Name, namespace.Name)
continue
}
err = ReplaceArtifactRepositoryType(client, namespace, workflowTemplate, nil)
if err != nil {
return err
}
if _, err := client.CreateWorkflowTemplate(namespace.Name, workflowTemplate); err != nil {
return err
}
}
// Update tf-od
// Create tf-od
workflowTemplate = &v1.WorkflowTemplate{
Name: tensorflowObjectDetectionWorkflowTemplateName,
Manifest: tensorflowObjectDetectionWorkflowTemplate,
@@ -488,7 +491,11 @@ func Up20200812104328(tx *sql.Tx) error {
}
for _, namespace := range namespaces {
if _, err := client.CreateWorkflowTemplateVersion(namespace.Name, workflowTemplate); err != nil {
err = ReplaceArtifactRepositoryType(client, namespace, workflowTemplate, nil)
if err != nil {
return err
}
if _, err := client.CreateWorkflowTemplate(namespace.Name, workflowTemplate); err != nil {
return err
}
}

View File

@@ -180,12 +180,6 @@ func Up20200812113316(tx *sql.Tx) error {
if err != nil {
return err
}
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate5,
Description: "Powerful and efficient Computer Vision Annotation Tool (CVAT)",
}
for _, namespace := range namespaces {
artifactRepositoryType := "s3"
@@ -196,6 +190,12 @@ func Up20200812113316(tx *sql.Tx) error {
if nsConfig.ArtifactRepository.GCS != nil {
artifactRepositoryType = "gcs"
}
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate5,
Description: "Powerful and efficient Computer Vision Annotation Tool (CVAT)",
}
workspaceTemplate.Manifest = strings.NewReplacer(
"{{.ArtifactRepositoryType}}", artifactRepositoryType).Replace(workspaceTemplate.Manifest)
if _, err := client.UpdateWorkspaceTemplate(namespace.Name, workspaceTemplate); err != nil {

View File

@@ -0,0 +1,163 @@
package migration
import (
"database/sql"
v1 "github.com/onepanelio/core/pkg"
uid2 "github.com/onepanelio/core/pkg/util/uid"
"github.com/pressly/goose"
)
const jupyterWorkspaceTemplate2 = `# Docker containers that are part of the Workspace
containers:
- name: jupyterlab-tensorflow
image: onepanel/jupyterlab:1.0.1
command: ["/bin/bash", "-c", "start.sh jupyter lab --LabApp.token='' --LabApp.allow_remote_access=True --LabApp.allow_origin=\"*\" --LabApp.disable_check_xsrf=True --LabApp.trust_xheaders=True --LabApp.base_url=/ --LabApp.tornado_settings='{\"headers\":{\"Content-Security-Policy\":\"frame-ancestors * \'self\'\"}}' --notebook-dir='/data' --allow-root"]
env:
- name: tornado
value: "'{'headers':{'Content-Security-Policy':\"frame-ancestors\ *\ \'self'\"}}'"
args:
ports:
- containerPort: 8888
name: jupyterlab
- containerPort: 6006
name: tensorboard
volumeMounts:
- name: data
mountPath: /data
ports:
- name: jupyterlab
port: 80
protocol: TCP
targetPort: 8888
- name: tensorboard
port: 6006
protocol: TCP
targetPort: 6006
routes:
- match:
- uri:
prefix: /tensorboard
route:
- destination:
port:
number: 6006
- match:
- uri:
prefix: / #jupyter runs at the default route
route:
- destination:
port:
number: 80
# DAG Workflow to be executed once a Workspace action completes (optional)
#postExecutionWorkflow:
# entrypoint: main
# templates:
# - name: main
# dag:
# tasks:
# - name: slack-notify
# template: slack-notify
# - name: slack-notify
# container:
# image: technosophos/slack-notify
# args:
# - SLACK_USERNAME=onepanel SLACK_TITLE="Your workspace is ready" SLACK_ICON=https://www.gravatar.com/avatar/5c4478592fe00878f62f0027be59c1bd SLACK_MESSAGE="Your workspace is now running" ./slack-notify
# command:
# - sh
# - -c
`
func initialize20200821162630() {
if _, ok := initializedMigrations[20200821162630]; !ok {
goose.AddMigration(Up20200821162630, Down20200821162630)
initializedMigrations[20200821162630] = true
}
}
//Up20200821162630 updates jupyterlab workspace with new features.
// Tensorflow 2.3 compiled to support CUDA 10.2 and cudnn8
// Pytorch with GPU support.
// OpenCV compiled from source with CUDA support.
// Miniconda, Jupyterlab 2.2+, and lots of neat extensions.
func Up20200821162630(tx *sql.Tx) error {
// This code is executed when the migration is applied.
client, err := getClient()
if err != nil {
return err
}
defer client.DB.Close()
migrationsRan, err := getRanSQLMigrations(client)
if err != nil {
return err
}
if _, ok := migrationsRan[20200821162630]; ok {
return nil
}
namespaces, err := client.ListOnepanelEnabledNamespaces()
if err != nil {
return err
}
uid, err := uid2.GenerateUID(jupyterLabTemplateName, 30)
if err != nil {
return err
}
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: jupyterLabTemplateName,
Manifest: jupyterWorkspaceTemplate2,
}
for _, namespace := range namespaces {
if _, err := client.UpdateWorkspaceTemplate(namespace.Name, workspaceTemplate); err != nil {
return err
}
}
return nil
}
// Down20200821162630 removes the JupyterLab template update
func Down20200821162630(tx *sql.Tx) error {
// This code is executed when the migration is rolled back.
client, err := getClient()
if err != nil {
return err
}
defer client.DB.Close()
migrationsRan, err := getRanSQLMigrations(client)
if err != nil {
return err
}
if _, ok := migrationsRan[20200821162630]; ok {
return nil
}
namespaces, err := client.ListOnepanelEnabledNamespaces()
if err != nil {
return err
}
uid, err := uid2.GenerateUID(jupyterLabTemplateName, 30)
if err != nil {
return err
}
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: jupyterLabTemplateName,
Manifest: jupyterWorkspaceTemplate,
}
for _, namespace := range namespaces {
if _, err := client.UpdateWorkspaceTemplate(namespace.Name, workspaceTemplate); err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,251 @@
package migration
import (
"database/sql"
v1 "github.com/onepanelio/core/pkg"
"github.com/pressly/goose"
)
const maskRCNNTemplate2 = `arguments:
parameters:
- name: source
value: https://github.com/onepanelio/Mask_RCNN.git
displayName: Model source code
type: hidden
visibility: private
- name: cvat-annotation-path
value: annotation-dump/sample_dataset
hint: Path to annotated data in default object storage (i.e S3). In CVAT, this parameter will be pre-populated.
displayName: Dataset path
visibility: private
- name: cvat-output-path
value: workflow-data/output/sample_output
hint: Path to store output artifacts in default object storage (i.e s3). In CVAT, this parameter will be pre-populated.
displayName: Workflow output path
visibility: private
- name: cvat-finetune-checkpoint
value: ''
hint: Select the last fine-tune checkpoint for this model. It may take up to 5 minutes for a recent checkpoint show here. Leave empty if this is the first time you're training this model.
displayName: Checkpoint path
visibility: public
- name: cvat-num-classes
displayName: Number of classes
hint: Number of classes (i.e in CVAT taks) + 1 for background
value: 81
visibility: private
- name: hyperparameters
displayName: Hyperparameters
visibility: public
type: textarea.textarea
value: |-
stage-1-epochs=1 # Epochs for network heads
stage-2-epochs=2 # Epochs for finetune layers
stage-3-epochs=3 # Epochs for all layers
hint: "Please refer to our <a href='https://docs.onepanel.ai/docs/getting-started/use-cases/computervision/annotation/cvat/cvat_annotation_model#arguments-optional' target='_blank'>documentation</a> for more information on parameters. Number of classes will be automatically populated if you had 'sys-num-classes' parameter in a workflow."
- name: dump-format
value: cvat_coco
displayName: CVAT dump format
visibility: public
- name: tf-image
visibility: public
value: tensorflow/tensorflow:1.13.1-py3
type: select.select
displayName: Select TensorFlow image
hint: Select the GPU image if you are running on a GPU node pool
options:
- name: 'TensorFlow 1.13.1 CPU Image'
value: 'tensorflow/tensorflow:1.13.1-py3'
- name: 'TensorFlow 1.13.1 GPU Image'
value: 'tensorflow/tensorflow:1.13.1-gpu-py3'
- displayName: Node pool
hint: Name of node pool or group to run this workflow task
type: select.select
visibility: public
name: sys-node-pool
value: Standard_D4s_v3
required: true
options:
- name: 'CPU: 2, RAM: 8GB'
value: Standard_D2s_v3
- name: 'CPU: 4, RAM: 16GB'
value: Standard_D4s_v3
- name: 'GPU: 1xK80, CPU: 6, RAM: 56GB'
value: Standard_NC6
entrypoint: main
templates:
- dag:
tasks:
- name: train-model
template: tensorflow
# Uncomment the lines below if you want to send Slack notifications
# - arguments:
# artifacts:
# - from: '{{tasks.train-model.outputs.artifacts.sys-metrics}}'
# name: metrics
# parameters:
# - name: status
# value: '{{tasks.train-model.status}}'
# dependencies:
# - train-model
# name: notify-in-slack
# template: slack-notify-success
name: main
- container:
args:
- |
apt-get update \
&& apt-get install -y git wget libglib2.0-0 libsm6 libxext6 libxrender-dev \
&& pip install -r requirements.txt \
&& pip install boto3 pyyaml google-cloud-storage \
&& git clone https://github.com/waleedka/coco \
&& cd coco/PythonAPI \
&& python setup.py build_ext install \
&& rm -rf build \
&& cd ../../ \
&& wget https://github.com/matterport/Mask_RCNN/releases/download/v2.0/mask_rcnn_coco.h5 \
&& python setup.py install && ls \
&& python samples/coco/cvat.py train --dataset=/mnt/data/datasets \
--model=workflow_maskrcnn \
--extras="{{workflow.parameters.hyperparameters}}" \
--ref_model_path="{{workflow.parameters.cvat-finetune-checkpoint}}" \
--num_classes="{{workflow.parameters.cvat-num-classes}}" \
&& cd /mnt/src/ \
&& python prepare_dataset.py /mnt/data/datasets/annotations/instances_default.json
command:
- sh
- -c
image: '{{workflow.parameters.tf-image}}'
volumeMounts:
- mountPath: /mnt/data
name: data
- mountPath: /mnt/output
name: output
workingDir: /mnt/src
nodeSelector:
beta.kubernetes.io/instance-type: '{{workflow.parameters.sys-node-pool}}'
inputs:
artifacts:
- name: data
path: /mnt/data/datasets/
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.cvat-annotation-path}}'
- git:
repo: '{{workflow.parameters.source}}'
revision: "no-boto"
name: src
path: /mnt/src
name: tensorflow
outputs:
artifacts:
- name: model
optional: true
path: /mnt/output
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.cvat-output-path}}/{{workflow.name}}'
# Uncomment the lines below if you want to send Slack notifications
#- container:
# args:
# - SLACK_USERNAME=Onepanel SLACK_TITLE="{{workflow.name}} {{inputs.parameters.status}}"
# SLACK_ICON=https://www.gravatar.com/avatar/5c4478592fe00878f62f0027be59c1bd
# SLACK_MESSAGE=$(cat /tmp/metrics.json)} ./slack-notify
# command:
# - sh
# - -c
# image: technosophos/slack-notify
# inputs:
# artifacts:
# - name: metrics
# optional: true
# path: /tmp/metrics.json
# parameters:
# - name: status
# name: slack-notify-success
volumeClaimTemplates:
- metadata:
creationTimestamp: null
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi
- metadata:
creationTimestamp: null
name: output
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi`
func initialize20200824095513() {
if _, ok := initializedMigrations[20200824095513]; !ok {
goose.AddMigration(Up20200824095513, Down20200824095513)
initializedMigrations[20200824095513] = true
}
}
// Up20200824095513 updates the maskrcnn workflow template
func Up20200824095513(tx *sql.Tx) error {
// This code is executed when the migration is applied.
client, err := getClient()
if err != nil {
return err
}
defer client.DB.Close()
migrationsRan, err := getRanSQLMigrations(client)
if err != nil {
return err
}
if _, ok := migrationsRan[20200824095513]; ok {
return nil
}
namespaces, err := client.ListOnepanelEnabledNamespaces()
if err != nil {
return err
}
// Update maskrcnn
workflowTemplate := &v1.WorkflowTemplate{
Name: maskRCNNWorkflowTemplateName,
Manifest: maskRCNNTemplate2,
Labels: map[string]string{
"used-by": "cvat",
},
}
if err := workflowTemplate.GenerateUID(workflowTemplate.Name); err != nil {
return err
}
for _, namespace := range namespaces {
err = ReplaceArtifactRepositoryType(client, namespace, workflowTemplate, nil)
if err != nil {
return err
}
if _, err := client.CreateWorkflowTemplateVersion(namespace.Name, workflowTemplate); err != nil {
return err
}
}
return nil
}
// Down20200824095513 does nothing
func Down20200824095513(tx *sql.Tx) error {
// This code is executed when the migration is rolled back.
return nil
}

View File

@@ -0,0 +1,281 @@
package migration
import (
"database/sql"
v1 "github.com/onepanelio/core/pkg"
"github.com/pressly/goose"
)
const tensorflowObjectDetectionTraining2 = `arguments:
parameters:
- name: source
value: https://github.com/tensorflow/models.git
displayName: Model source code
type: hidden
visibility: private
- name: trainingsource
value: https://github.com/onepanelio/cvat-training.git
type: hidden
visibility: private
- name: revision
value: v1.13.0
type: hidden
visibility: private
- name: cvat-annotation-path
value: annotation-dump/sample_dataset
displayName: Dataset path
hint: Path to annotated data in default object storage (i.e S3). In CVAT, this parameter will be pre-populated.
visibility: private
- name: cvat-output-path
value: workflow-data/output/sample_output
hint: Path to store output artifacts in default object storage (i.e s3). In CVAT, this parameter will be pre-populated.
displayName: Workflow output path
visibility: private
- name: cvat-model
value: frcnn-res50-coco
displayName: Model
hint: TF Detection API's model to use for training.
type: select.select
visibility: public
options:
- name: 'Faster RCNN-ResNet 101-COCO'
value: frcnn-res101-coco
- name: 'Faster RCNN-ResNet 101-Low Proposal-COCO'
value: frcnn-res101-low
- name: 'Faster RCNN-ResNet 50-COCO'
value: frcnn-res50-coco
- name: 'Faster RCNN-NAS-COCO'
value: frcnn-nas-coco
- name: 'SSD MobileNet V1-COCO'
value: ssd-mobilenet-v1-coco2
- name: 'SSD MobileNet V2-COCO'
value: ssd-mobilenet-v2-coco
- name: 'SSDLite MobileNet-COCO'
value: ssdlite-mobilenet-coco
- name: hyperparameters
value: |-
num-steps=10000
displayName: Hyperparameters
visibility: public
type: textarea.textarea
hint: "Please refer to our <a href='https://docs.onepanel.ai/docs/getting-started/use-cases/computervision/annotation/cvat/cvat_annotation_model#arguments-optional' target='_blank'>documentation</a> for more information on parameters. Number of classes will be automatically populated if you had 'sys-num-classes' parameter in a workflow."
- name: cvat-finetune-checkpoint
value: ''
hint: Select the last fine-tune checkpoint for this model. It may take up to 5 minutes for a recent checkpoint show here. Leave empty if this is the first time you're training this model.
displayName: Checkpoint path
visibility: public
- name: cvat-num-classes
value: 81
hint: Number of classes
displayName: Number of classes
visibility: private
- name: tf-image
value: tensorflow/tensorflow:1.13.1-py3
type: select.select
displayName: Select TensorFlow image
visibility: public
hint: Select the GPU image if you are running on a GPU node pool
options:
- name: 'TensorFlow 1.13.1 CPU Image'
value: 'tensorflow/tensorflow:1.13.1-py3'
- name: 'TensorFlow 1.13.1 GPU Image'
value: 'tensorflow/tensorflow:1.13.1-gpu-py3'
- displayName: Node pool
hint: Name of node pool or group to run this workflow task
type: select.select
name: sys-node-pool
value: Standard_D4s_v3
visibility: public
required: true
options:
- name: 'CPU: 2, RAM: 8GB'
value: Standard_D2s_v3
- name: 'CPU: 4, RAM: 16GB'
value: Standard_D4s_v3
- name: 'GPU: 1xK80, CPU: 6, RAM: 56GB'
value: Standard_NC6
- name: dump-format
value: cvat_tfrecord
visibility: public
entrypoint: main
templates:
- dag:
tasks:
- name: train-model
template: tensorflow
# Uncomment the lines below if you want to send Slack notifications
# - arguments:
# artifacts:
# - from: '{{tasks.train-model.outputs.artifacts.sys-metrics}}'
# name: metrics
# parameters:
# - name: status
# value: '{{tasks.train-model.status}}'
# dependencies:
# - train-model
# name: notify-in-slack
# template: slack-notify-success
name: main
- container:
args:
- |
apt-get update && \
apt-get install -y python3-pip git wget unzip libglib2.0-0 libsm6 libxext6 libxrender-dev && \
pip install pillow lxml Cython contextlib2 jupyter matplotlib numpy scipy boto3 pycocotools pyyaml google-cloud-storage && \
cd /mnt/src/tf/research && \
export PYTHONPATH=$PYTHONPATH:` + "`pwd`:`pwd`" + `/slim && \
cd /mnt/src/train && \
python convert_workflow.py \
--extras="{{workflow.parameters.hyperparameters}}" \
--model="{{workflow.parameters.cvat-model}}" \
--num_classes="{{workflow.parameters.cvat-num-classes}}" \
--sys_finetune_checkpoint={{workflow.parameters.cvat-finetune-checkpoint}}
command:
- sh
- -c
image: '{{workflow.parameters.tf-image}}'
volumeMounts:
- mountPath: /mnt/data
name: data
- mountPath: /mnt/output
name: output
workingDir: /mnt/src
nodeSelector:
beta.kubernetes.io/instance-type: '{{workflow.parameters.sys-node-pool}}'
inputs:
artifacts:
- name: data
path: /mnt/data/datasets/
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.cvat-annotation-path}}'
- name: models
path: /mnt/data/models/
optional: true
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.cvat-finetune-checkpoint}}'
- git:
repo: '{{workflow.parameters.source}}'
revision: '{{workflow.parameters.revision}}'
name: src
path: /mnt/src/tf
- git:
repo: '{{workflow.parameters.trainingsource}}'
revision: 'optional-artifacts'
name: tsrc
path: /mnt/src/train
name: tensorflow
outputs:
artifacts:
- name: model
optional: true
path: /mnt/output
{{.ArtifactRepositoryType}}:
key: '{{workflow.namespace}}/{{workflow.parameters.cvat-output-path}}/{{workflow.name}}'
# Uncomment the lines below if you want to send Slack notifications
#- container:
# args:
# - SLACK_USERNAME=Onepanel SLACK_TITLE="{{workflow.name}} {{inputs.parameters.status}}"
# SLACK_ICON=https://www.gravatar.com/avatar/5c4478592fe00878f62f0027be59c1bd
# SLACK_MESSAGE=$(cat /tmp/metrics.json)} ./slack-notify
# command:
# - sh
# - -c
# image: technosophos/slack-notify
# inputs:
# artifacts:
# - name: metrics
# optional: true
# path: /tmp/metrics.json
# parameters:
# - name: status
# name: slack-notify-success
volumeClaimTemplates:
- metadata:
creationTimestamp: null
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi
- metadata:
creationTimestamp: null
name: output
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi`
func initialize20200824101019() {
if _, ok := initializedMigrations[20200824101019]; !ok {
goose.AddMigration(Up20200824101019, Down20200824101019)
initializedMigrations[20200824101019] = true
}
}
// Up20200824101019 updates the tf object detection training workflow template
func Up20200824101019(tx *sql.Tx) error {
// This code is executed when the migration is applied.
client, err := getClient()
if err != nil {
return err
}
defer client.DB.Close()
migrationsRan, err := getRanSQLMigrations(client)
if err != nil {
return err
}
if _, ok := migrationsRan[20200824101019]; ok {
return nil
}
namespaces, err := client.ListOnepanelEnabledNamespaces()
if err != nil {
return err
}
// Update tfObjectDetectionTraining
workflowTemplate := &v1.WorkflowTemplate{
Name: tensorflowObjectDetectionWorkflowTemplateName,
Manifest: tensorflowObjectDetectionTraining2,
Labels: map[string]string{
"used-by": "cvat",
},
}
if err := workflowTemplate.GenerateUID(workflowTemplate.Name); err != nil {
return err
}
for _, namespace := range namespaces {
err = ReplaceArtifactRepositoryType(client, namespace, workflowTemplate, nil)
if err != nil {
return err
}
if _, err := client.CreateWorkflowTemplateVersion(namespace.Name, workflowTemplate); err != nil {
return err
}
}
return nil
}
// Down20200824101019 does nothing
func Down20200824101019(tx *sql.Tx) error {
// This code is executed when the migration is rolled back.
return nil
}

View File

@@ -0,0 +1,206 @@
package migration
import (
"database/sql"
v1 "github.com/onepanelio/core/pkg"
uid2 "github.com/onepanelio/core/pkg/util/uid"
"github.com/pressly/goose"
)
const cvatWorkspaceTemplate6 = `# Workspace arguments
arguments:
parameters:
- name: sync-directory
displayName: Directory to sync raw input and training output
value: workflow-data
hint: Location to sync raw input, models and checkpoints from default object storage. Note that this will be relative to the current namespace.
containers:
- name: cvat-db
image: postgres:10-alpine
env:
- name: POSTGRES_USER
value: root
- name: POSTGRES_DB
value: cvat
- name: POSTGRES_HOST_AUTH_METHOD
value: trust
- name: PGDATA
value: /var/lib/psql/data
ports:
- containerPort: 5432
name: tcp
volumeMounts:
- name: db
mountPath: /var/lib/psql
- name: cvat-redis
image: redis:4.0-alpine
ports:
- containerPort: 6379
name: tcp
- name: cvat
image: onepanel/cvat:0.12.0-rc.6_cvat.1.0.0
env:
- name: DJANGO_MODWSGI_EXTRA_ARGS
value: ""
- name: ALLOWED_HOSTS
value: '*'
- name: CVAT_REDIS_HOST
value: localhost
- name: CVAT_POSTGRES_HOST
value: localhost
- name: CVAT_SHARE_URL
value: /home/django/data
- name: ONEPANEL_SYNC_DIRECTORY
value: '{{workspace.parameters.sync-directory}}'
- name: NVIDIA_VISIBLE_DEVICES
value: all
- name: NVIDIA_DRIVER_CAPABILITIES
value: compute,utility
- name: NVIDIA_REQUIRE_CUDA
value: "cuda>=10.0 brand=tesla,driver>=384,driver<385 brand=tesla,driver>=410,driver<411"
ports:
- containerPort: 8080
name: http
volumeMounts:
- name: data
mountPath: /home/django/data
- name: keys
mountPath: /home/django/keys
- name: logs
mountPath: /home/django/logs
- name: models
mountPath: /home/django/models
- name: share
mountPath: /home/django/share
- name: sys-namespace-config
mountPath: /etc/onepanel
readOnly: true
- name: cvat-ui
image: onepanel/cvat-ui:0.12.0-rc.1_cvat.1.0.0
ports:
- containerPort: 80
name: http
# You can add multiple FileSyncer sidecar containers if needed
- name: filesyncer
image: onepanel/filesyncer:{{.ArtifactRepositoryType}}
imagePullPolicy: Always
args:
- download
env:
- name: FS_PATH
value: /mnt/share
- name: FS_PREFIX
value: '{{workflow.namespace}}/{{workspace.parameters.sync-directory}}'
volumeMounts:
- name: share
mountPath: /mnt/share
- name: sys-namespace-config
mountPath: /etc/onepanel
readOnly: true
ports:
- name: cvat-ui
port: 80
protocol: TCP
targetPort: 80
- name: cvat
port: 8080
protocol: TCP
targetPort: 8080
routes:
- match:
- uri:
regex: /api/.*|/git/.*|/tensorflow/.*|/onepanelio/.*|/tracking/.*|/auto_annotation/.*|/analytics/.*|/static/.*|/admin/.*|/documentation/.*|/dextr/.*|/reid/.*
- queryParams:
id:
regex: \d+.*
route:
- destination:
port:
number: 8080
timeout: 600s
- match:
- uri:
prefix: /
route:
- destination:
port:
number: 80
timeout: 600s
# DAG Workflow to be executed once a Workspace action completes (optional)
# Uncomment the lines below if you want to send Slack notifications
#postExecutionWorkflow:
# entrypoint: main
# templates:
# - name: main
# dag:
# tasks:
# - name: slack-notify
# template: slack-notify
# - name: slack-notify
# container:
# image: technosophos/slack-notify
# args:
# - SLACK_USERNAME=onepanel SLACK_TITLE="Your workspace is ready" SLACK_ICON=https://www.gravatar.com/avatar/5c4478592fe00878f62f0027be59c1bd SLACK_MESSAGE="Your workspace is now running" ./slack-notify
# command:
# - sh
# - -c`
func initialize20200824101905() {
if _, ok := initializedMigrations[20200824101905]; !ok {
goose.AddMigration(Up20200824101905, Down20200824101905)
initializedMigrations[20200824101905] = true
}
}
// Up20200824101905 updates the cvat workspace template
func Up20200824101905(tx *sql.Tx) error {
// This code is executed when the migration is applied.
client, err := getClient()
if err != nil {
return err
}
defer client.DB.Close()
migrationsRan, err := getRanSQLMigrations(client)
if err != nil {
return err
}
if _, ok := migrationsRan[20200824101905]; ok {
return nil
}
namespaces, err := client.ListOnepanelEnabledNamespaces()
if err != nil {
return err
}
uid, err := uid2.GenerateUID(cvatTemplateName, 30)
if err != nil {
return err
}
for _, namespace := range namespaces {
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate6,
Description: "Powerful and efficient Computer Vision Annotation Tool (CVAT)",
}
err = ReplaceArtifactRepositoryType(client, namespace, nil, workspaceTemplate)
if err != nil {
return err
}
if _, err := client.UpdateWorkspaceTemplate(namespace.Name, workspaceTemplate); err != nil {
return err
}
}
return nil
}
// Down20200824101905 does nothing
func Down20200824101905(tx *sql.Tx) error {
// This code is executed when the migration is rolled back.
return nil
}

View File

@@ -0,0 +1,206 @@
package migration
import (
"database/sql"
v1 "github.com/onepanelio/core/pkg"
uid2 "github.com/onepanelio/core/pkg/util/uid"
"github.com/pressly/goose"
)
const cvatWorkspaceTemplate7 = `# Workspace arguments
arguments:
parameters:
- name: sync-directory
displayName: Directory to sync raw input and training output
value: workflow-data
hint: Location to sync raw input, models and checkpoints from default object storage. Note that this will be relative to the current namespace.
containers:
- name: cvat-db
image: postgres:10-alpine
env:
- name: POSTGRES_USER
value: root
- name: POSTGRES_DB
value: cvat
- name: POSTGRES_HOST_AUTH_METHOD
value: trust
- name: PGDATA
value: /var/lib/psql/data
ports:
- containerPort: 5432
name: tcp
volumeMounts:
- name: db
mountPath: /var/lib/psql
- name: cvat-redis
image: redis:4.0-alpine
ports:
- containerPort: 6379
name: tcp
- name: cvat
image: onepanel/cvat:0.12.0_cvat.1.0.0
env:
- name: DJANGO_MODWSGI_EXTRA_ARGS
value: ""
- name: ALLOWED_HOSTS
value: '*'
- name: CVAT_REDIS_HOST
value: localhost
- name: CVAT_POSTGRES_HOST
value: localhost
- name: CVAT_SHARE_URL
value: /home/django/data
- name: ONEPANEL_SYNC_DIRECTORY
value: '{{workspace.parameters.sync-directory}}'
- name: NVIDIA_VISIBLE_DEVICES
value: all
- name: NVIDIA_DRIVER_CAPABILITIES
value: compute,utility
- name: NVIDIA_REQUIRE_CUDA
value: "cuda>=10.0 brand=tesla,driver>=384,driver<385 brand=tesla,driver>=410,driver<411"
ports:
- containerPort: 8080
name: http
volumeMounts:
- name: data
mountPath: /home/django/data
- name: keys
mountPath: /home/django/keys
- name: logs
mountPath: /home/django/logs
- name: models
mountPath: /home/django/models
- name: share
mountPath: /home/django/share
- name: sys-namespace-config
mountPath: /etc/onepanel
readOnly: true
- name: cvat-ui
image: onepanel/cvat-ui:0.12.0_cvat.1.0.0
ports:
- containerPort: 80
name: http
# You can add multiple FileSyncer sidecar containers if needed
- name: filesyncer
image: onepanel/filesyncer:{{.ArtifactRepositoryType}}
imagePullPolicy: Always
args:
- download
env:
- name: FS_PATH
value: /mnt/share
- name: FS_PREFIX
value: '{{workflow.namespace}}/{{workspace.parameters.sync-directory}}'
volumeMounts:
- name: share
mountPath: /mnt/share
- name: sys-namespace-config
mountPath: /etc/onepanel
readOnly: true
ports:
- name: cvat-ui
port: 80
protocol: TCP
targetPort: 80
- name: cvat
port: 8080
protocol: TCP
targetPort: 8080
routes:
- match:
- uri:
regex: /api/.*|/git/.*|/tensorflow/.*|/onepanelio/.*|/tracking/.*|/auto_annotation/.*|/analytics/.*|/static/.*|/admin/.*|/documentation/.*|/dextr/.*|/reid/.*
- queryParams:
id:
regex: \d+.*
route:
- destination:
port:
number: 8080
timeout: 600s
- match:
- uri:
prefix: /
route:
- destination:
port:
number: 80
timeout: 600s
# DAG Workflow to be executed once a Workspace action completes (optional)
# Uncomment the lines below if you want to send Slack notifications
#postExecutionWorkflow:
# entrypoint: main
# templates:
# - name: main
# dag:
# tasks:
# - name: slack-notify
# template: slack-notify
# - name: slack-notify
# container:
# image: technosophos/slack-notify
# args:
# - SLACK_USERNAME=onepanel SLACK_TITLE="Your workspace is ready" SLACK_ICON=https://www.gravatar.com/avatar/5c4478592fe00878f62f0027be59c1bd SLACK_MESSAGE="Your workspace is now running" ./slack-notify
# command:
# - sh
# - -c`
func initialize20200825154403() {
if _, ok := initializedMigrations[20200825154403]; !ok {
goose.AddMigration(Up20200825154403, Down20200825154403)
initializedMigrations[20200825154403] = true
}
}
// Up20200825154403 runs the migration to upgrade the cvat workspace template
func Up20200825154403(tx *sql.Tx) error {
// This code is executed when the migration is applied.
client, err := getClient()
if err != nil {
return err
}
defer client.DB.Close()
migrationsRan, err := getRanSQLMigrations(client)
if err != nil {
return err
}
if _, ok := migrationsRan[20200825154403]; ok {
return nil
}
namespaces, err := client.ListOnepanelEnabledNamespaces()
if err != nil {
return err
}
uid, err := uid2.GenerateUID(cvatTemplateName, 30)
if err != nil {
return err
}
for _, namespace := range namespaces {
workspaceTemplate := &v1.WorkspaceTemplate{
UID: uid,
Name: cvatTemplateName,
Manifest: cvatWorkspaceTemplate7,
Description: "Powerful and efficient Computer Vision Annotation Tool (CVAT)",
}
err = ReplaceArtifactRepositoryType(client, namespace, nil, workspaceTemplate)
if err != nil {
return err
}
if _, err := client.UpdateWorkspaceTemplate(namespace.Name, workspaceTemplate); err != nil {
return err
}
}
return nil
}
// Down20200825154403 does nothing
func Down20200825154403(tx *sql.Tx) error {
// This code is executed when the migration is rolled back.
return nil
}

View File

@@ -1,10 +1,12 @@
package migration
import (
"errors"
sq "github.com/Masterminds/squirrel"
"github.com/jmoiron/sqlx"
v1 "github.com/onepanelio/core/pkg"
"log"
"strings"
)
// initializedMigrations is used to keep track of which migrations have been initialized.
@@ -48,6 +50,11 @@ func Initialize() {
initialize20200812104328()
initialize20200812113316()
initialize20200814160856()
initialize20200821162630()
initialize20200824095513()
initialize20200824101019()
initialize20200824101905()
initialize20200825154403()
if err := client.DB.Close(); err != nil {
log.Printf("[error] closing db %v", err)
@@ -90,3 +97,29 @@ func getRanSQLMigrations(client *v1.Client) (map[uint64]bool, error) {
return result, nil
}
// ReplaceArtifactRepositoryType will look for {{.ArtifactRepositoryType}} in the migration and replace it based on config.
func ReplaceArtifactRepositoryType(client *v1.Client, namespace *v1.Namespace, workflowTemplate *v1.WorkflowTemplate, workspaceTemplate *v1.WorkspaceTemplate) error {
artifactRepositoryType := "s3"
nsConfig, err := client.GetNamespaceConfig(namespace.Name)
if err != nil {
return err
}
if nsConfig.ArtifactRepository.GCS != nil {
artifactRepositoryType = "gcs"
}
if workflowTemplate != nil {
workflowTemplate.Manifest = strings.NewReplacer(
"{{.ArtifactRepositoryType}}", artifactRepositoryType).Replace(workflowTemplate.Manifest)
}
if workspaceTemplate != nil {
workspaceTemplate.Manifest = strings.NewReplacer(
"{{.ArtifactRepositoryType}}", artifactRepositoryType).Replace(workspaceTemplate.Manifest)
}
if workflowTemplate == nil && workspaceTemplate == nil {
return errors.New("workflow and workspace template cannot be nil")
}
return nil
}

View File

@@ -3,6 +3,7 @@ package auth
import (
"context"
"errors"
"fmt"
"github.com/onepanelio/core/api"
"net/http"
"strings"
@@ -85,12 +86,13 @@ func IsAuthorized(c *v1.Client, namespace, verb, group, resource, name string) (
},
})
deniedMsg := fmt.Sprintf(`Permission denied. Namespace: '%v', Verb: '%v', Group: '%v', Resource '%v', Name: '%v'`, namespace, verb, group, resource, name)
if err != nil {
return false, status.Error(codes.PermissionDenied, "Permission denied.")
return false, status.Error(codes.PermissionDenied, deniedMsg)
}
allowed = review.Status.Allowed
if !allowed {
return false, status.Error(codes.PermissionDenied, "Permission denied.")
return false, status.Error(codes.PermissionDenied, deniedMsg)
}
return

View File

@@ -2,8 +2,10 @@ package server
import (
"context"
"fmt"
"github.com/onepanelio/core/api"
v1 "github.com/onepanelio/core/pkg"
"github.com/onepanelio/core/pkg/util"
"github.com/onepanelio/core/server/auth"
"github.com/pkg/errors"
"google.golang.org/grpc/codes"
@@ -41,7 +43,7 @@ func (a *AuthServer) IsAuthorized(ctx context.Context, request *api.IsAuthorized
allowed, err := auth.IsAuthorized(client, request.IsAuthorized.Namespace, request.IsAuthorized.Verb, request.IsAuthorized.Group, request.IsAuthorized.Resource, request.IsAuthorized.ResourceName)
if err != nil {
res.Authorized = false
return res, err
return res, util.NewUserError(codes.PermissionDenied, fmt.Sprintf("Namespace: %v, Verb: %v, Group: \"%v\", Resource: %v. Source: %v", request.IsAuthorized.Namespace, request.IsAuthorized.Verb, request.IsAuthorized.Group, request.IsAuthorized.ResourceName, err))
}
res.Authorized = allowed