Merge remote-tracking branch 'origin/master' into add-adoc-export

This commit is contained in:
Christian Richter
2022-05-04 10:55:07 +02:00
328 changed files with 9993 additions and 8820 deletions

View File

@@ -3,5 +3,5 @@ CORE_COMMITID=4ee9352f4df70cb49cdd539f5a6f0275d369605a
CORE_BRANCH=master
# The test runner source for UI tests
WEB_COMMITID=41c62d459c4e7bc4a04367eb80f45a8c29aa3baa
WEB_COMMITID=4d0b216f0ef6ad9708d414aca60920fdb877e5ab
WEB_BRANCH=master

View File

@@ -44,17 +44,34 @@ config = {
"modules": [
# if you add a module here please also add it to the root level Makefile
"extensions/accounts",
"extensions/app-provider",
"extensions/app-registry",
"extensions/audit",
"extensions/auth-basic",
"extensions/auth-bearer",
"extensions/auth-machine",
"extensions/frontend",
"extensions/gateway",
"extensions/glauth",
"extensions/graph-explorer",
"extensions/graph",
"extensions/group",
"extensions/idm",
"extensions/idp",
"extensions/nats",
"extensions/notifications",
"extensions/ocdav",
"extensions/ocs",
"extensions/proxy",
"extensions/settings",
"extensions/storage",
"extensions/sharing",
"extensions/storage-metadata",
"extensions/storage-publiclink",
"extensions/storage-shares",
"extensions/storage-users",
"extensions/store",
"extensions/thumbnails",
"extensions/user",
"extensions/web",
"extensions/webdav",
"ocis-pkg",
@@ -110,12 +127,6 @@ config = {
"cron": "nightly",
},
},
"graphApiTests": {
"skip": True,
"earlyFali": False,
"numberOfParts": 10,
"skipExceptParts": [],
},
"rocketchat": {
"channel": "ocis-internal",
"from_secret": "private_rocketchat",
@@ -301,9 +312,6 @@ def testPipelines(ctx):
if "skip" not in config["parallelApiTests"] or not config["parallelApiTests"]["skip"]:
pipelines += parallelDeployAcceptancePipeline(ctx)
if "skip" not in config["graphApiTests"] or not config["graphApiTests"]["skip"]:
pipelines += graphApiAcceptancePipeline(ctx)
return pipelines
def testOcisModule(ctx, module):
@@ -573,7 +581,7 @@ def cs3ApiTests(ctx, storage, accounts_hash_difficulty = 4):
def coreApiTests(ctx, part_number = 1, number_of_parts = 1, storage = "ocis", accounts_hash_difficulty = 4):
early_fail = config["apiTests"]["earlyFail"] if "earlyFail" in config["apiTests"] else False
filterTags = "~@skipOnGraph&&~@skipOnOcis&&~@notToImplementOnOCIS&&~@toImplementOnOCIS&&~comments-app-required&&~@federation-app-required&&~@notifications-app-required&&~systemtags-app-required&&~@local_storage&&~@skipOnOcis-%s-Storage&&~@issue-ocis-3023" % ("OC" if storage == "owncloud" else "OCIS")
expectedFailuresFile = "/drone/src/tests/acceptance/expected-failures-graphAPI-on-%s-storage.md" % (storage.upper())
expectedFailuresFile = "/drone/src/tests/acceptance/expected-failures-API-on-%s-storage.md" % (storage.upper())
return {
"kind": "pipeline",
@@ -1629,73 +1637,6 @@ def notify(ctx):
},
}
def ocisServerWithAccounts(storage, accounts_hash_difficulty = 4, volumes = [], depends_on = []):
environment = {
"GRAPH_IDENTITY_BACKEND": "cs3",
"GRAPH_LDAP_SERVER_WRITE_ENABLED": "false",
"LDAP_URI": "ldaps://0.0.0.0:9126",
"LDAP_INSECURE": "true",
"LDAP_BIND_DN": "cn=admin,dc=ocis,dc=test",
"LDAP_BIND_PASSWORD": "admin",
"LDAP_USER_BASE_DN": "dc=ocis,dc=test",
"LDAP_USER_SCHEMA_ID": "ownclouduuid",
"LDAP_USER_SCHEMA_MAIL": "mail",
"LDAP_USER_SCHEMA_USERNAME": "cn",
"LDAP_USER_OBJECTCLASS": "posixAccount",
"LDAP_GROUP_BASE_DN": "dc=ocis,dc=test",
"LDAP_GROUP_SCHEMA_ID": "cn",
"LDAP_GROUP_SCHEMA_MAIL": "mail",
"LDAP_GROUP_SCHEMA_GROUPNAME": "cn",
"LDAP_GROUP_SCHEMA_MEMBER": "cn",
"LDAP_GROUP_OBJECTCLASS": "posixGroup",
"IDP_LDAP_BIND_DN": "cn=admin,dc=ocis,dc=test",
"LDAP_CACERT": "/root/.ocis/ldap/ldap.crt",
"IDP_LDAP_BIND_PASSWORD": "admin",
"IDP_LDAP_LOGIN_ATTRIBUTE": "uid",
"PROXY_ACCOUNT_BACKEND_TYPE": "accounts",
"OCS_ACCOUNT_BACKEND_TYPE": "accounts",
"OCIS_RUN_EXTENSIONS": "settings,storage-metadata,graph,graph-explorer,ocs,store,thumbnails,web,webdav,frontend,gateway,user,group,auth-basic,auth-bearer,auth-machine,storage-users,storage-shares,storage-publiclink,appprovider,sharing,proxy,idp,nats,accounts,glauth,ocdav",
"OCIS_INSECURE": "true",
"PROXY_ENABLE_BASIC_AUTH": "true",
"IDP_INSECURE": "true",
"OCIS_LOG_LEVEL": "error",
"OCIS_URL": "https://ocis-server:9200",
"ACCOUNTS_DEMO_USERS_AND_GROUPS": True,
"STORAGE_HOME_DRIVER": "%s" % (storage),
"STORAGE_USERS_DRIVER": "%s" % (storage),
"WEB_UI_CONFIG": "/drone/src/tests/config/drone/ocis-config.json",
}
# Pass in "default" accounts_hash_difficulty to not set this environment variable.
# That will allow OCIS to use whatever its built-in default is.
# Otherwise pass in a value from 4 to about 11 or 12 (default 4, for making regular tests fast)
# The high values cause lots of CPU to be used when hashing passwords, and really slow down the tests.
if (accounts_hash_difficulty != "default"):
environment["ACCOUNTS_HASH_DIFFICULTY"] = accounts_hash_difficulty
return [
{
"name": "ocis-server",
"image": OC_CI_ALPINE,
"detach": True,
"environment": environment,
"commands": [
"ocis/bin/ocis init --insecure true",
"ocis/bin/ocis server",
],
"volumes": volumes,
"depends_on": depends_on,
},
{
"name": "wait-for-ocis-server",
"image": OC_CI_ALPINE,
"commands": [
"curl -k -u admin:admin --fail --retry-connrefused --retry 10 --retry-all-errors 'https://ocis-server:9200/graph/v1.0/users/ddc2004c-0977-11eb-9d3f-a793888cd0f8'",
],
"depends_on": depends_on,
},
]
def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on = [], testing_parallel_deploy = False):
if not testing_parallel_deploy:
user = "0:0"
@@ -1763,28 +1704,24 @@ def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on =
"LDAP_LOGIN_ATTRIBUTES": "uid,mail",
# ownCloudSQL storage driver
"STORAGE_USERS_DRIVER": "owncloudsql",
"STORAGE_METADATA_DRIVER": "ocis",
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_DATADIR": "/mnt/data/files",
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_UPLOADINFO_DIR": "/tmp",
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_SHARE_FOLDER": "/Shares",
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_LAYOUT": "{{.Username}}",
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_DBUSERNAME": "owncloud",
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_DBPASSWORD": "owncloud",
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_DBHOST": "oc10-db",
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_DBPORT": 3306,
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_DBNAME": "owncloud",
# TODO: redis is not yet supported
"STORAGE_USERS_DRIVER_OWNCLOUDSQL_REDIS_ADDR": "redis:6379",
"STORAGE_USERS_OWNCLOUDSQL_DATADIR": "/mnt/data/files",
"STORAGE_USERS_OWNCLOUDSQL_SHARE_FOLDER": "/Shares",
"STORAGE_USERS_OWNCLOUDSQL_LAYOUT": "{{.Username}}",
"STORAGE_USERS_OWNCLOUDSQL_DB_USERNAME": "owncloud",
"STORAGE_USERS_OWNCLOUDSQL_DB_PASSWORD": "owncloud",
"STORAGE_USERS_OWNCLOUDSQL_DB_HOST": "oc10-db",
"STORAGE_USERS_OWNCLOUDSQL_DB_PORT": 3306,
"STORAGE_USERS_OWNCLOUDSQL_DB_NAME": "owncloud",
# ownCloudSQL sharing driver
"SHARING_USER_DRIVER": "owncloudsql",
"SHARING_USER_SQL_USERNAME": "owncloud",
"SHARING_USER_SQL_PASSWORD": "owncloud",
"SHARING_USER_SQL_HOST": "oc10-db",
"SHARING_USER_SQL_PORT": 3306,
"SHARING_USER_SQL_NAME": "owncloud",
"SHARING_USER_OWNCLOUDSQL_DB_USERNAME": "owncloud",
"SHARING_USER_OWNCLOUDSQL_DB_PASSWORD": "owncloud",
"SHARING_USER_OWNCLOUDSQL_DB_HOST": "oc10-db",
"SHARING_USER_OWNCLOUDSQL_DB_PORT": 3306,
"SHARING_USER_OWNCLOUDSQL_DB_NAME": "owncloud",
# General oCIS config
# OCIS_RUN_EXTENSIONS specifies to start all extensions except glauth, idp and accounts. These are replaced by external services
"OCIS_RUN_EXTENSIONS": "settings,storage-metadata,graph,graph-explorer,ocs,store,thumbnails,web,webdav,frontend,gateway,user,group,auth-basic,auth-bearer,auth-machine,storage-users,storage-shares,storage-publiclink,appprovider,sharing,proxy,nats,ocdav",
"OCIS_RUN_EXTENSIONS": "settings,storage-metadata,graph,graph-explorer,ocs,store,thumbnails,web,webdav,frontend,gateway,user,group,auth-basic,auth-bearer,auth-machine,storage-users,storage-shares,storage-publiclink,app-provider,sharing,proxy,nats,ocdav",
"OCIS_LOG_LEVEL": "info",
"OCIS_URL": OCIS_URL,
"OCIS_BASE_DATA_PATH": "/mnt/data/ocis",
@@ -2492,74 +2429,6 @@ def parallelDeploymentOC10Server():
},
]
def graphApiAcceptancePipeline(ctx):
pipelines = []
debugParts = config["graphApiTests"]["skipExceptParts"]
debugPartsEnabled = (len(debugParts) != 0)
for runPart in range(1, config["graphApiTests"]["numberOfParts"] + 1):
if (not debugPartsEnabled or (debugPartsEnabled and runPart in debugParts)):
pipelines.append(
graphApiTests(ctx, runPart, config["graphApiTests"]["numberOfParts"]),
)
return pipelines
def graphApiTests(ctx, part_number = 1, number_of_parts = 1):
storage = "ocis"
early_fail = config["graphApiTests"]["earlyFail"] if "earlyFail" in config["graphApiTests"] else False
filterTags = "~@skipOnGraph&&~@skipOnOcis&&~@notToImplementOnOCIS&&~@toImplementOnOCIS&&~comments-app-required&&~@federation-app-required&&~@notifications-app-required&&~systemtags-app-required&&~@local_storage&&~@skipOnOcis-OCIS-Storage&&~@issue-ocis-3023"
expectedFailuresFile = "/drone/src/tests/acceptance/expected-failures-graphAPI-on-OCIS-storage.md"
return {
"kind": "pipeline",
"type": "docker",
"name": "Graph-Core-API-Tests-%s-storage-%s" % (storage, part_number),
"platform": {
"os": "linux",
"arch": "amd64",
},
"steps": skipIfUnchanged(ctx, "acceptance-tests") +
restoreBuildArtifactCache(ctx, "ocis-binary-amd64", "ocis/bin/ocis") +
ocisServer() +
cloneCoreRepos() + [
{
"name": "Graph-oC10ApiTests-%s-storage-%s" % (storage, part_number),
"image": OC_CI_PHP % DEFAULT_PHP_VERSION,
"environment": {
"TEST_WITH_GRAPH_API": "true",
"PATH_TO_OCIS": "/drone/src",
"PATH_TO_CORE": "/srv/app/testrunner",
"TEST_SERVER_URL": "https://ocis-server:9200",
"SKELETON_DIR": "/srv/app/tmp/testing/data/apiSkeleton",
"OCIS_SKELETON_STRATEGY": "upload",
"TEST_OCIS": "true",
"SEND_SCENARIO_LINE_REFERENCES": "true",
"STORAGE_DRIVER": storage,
"BEHAT_FILTER_TAGS": filterTags,
"DIVIDE_INTO_NUM_PARTS": number_of_parts,
"RUN_PART": part_number,
"UPLOAD_DELETE_WAIT_TIME": 0,
"EXPECTED_FAILURES_FILE": expectedFailuresFile,
},
"commands": [
"cd /srv/app/testrunner",
"make test-acceptance-api",
],
"volumes": [stepVolumeOC10Tests],
},
] + failEarly(ctx, early_fail),
"depends_on": getPipelineNames([buildOcisBinaryForTesting(ctx)]),
"trigger": {
"ref": [
"refs/heads/master",
"refs/tags/v*",
"refs/pull/**",
],
},
"volumes": [pipelineVolumeOC10Tests],
}
def ldapService():
return [{
"name": "openldap",
@@ -2607,6 +2476,7 @@ def copyConfigs():
# ocis proxy config
"mkdir -p /etc/ocis",
"cp %s/ocis/proxy.yaml /etc/ocis/proxy.yaml" % (PARALLEL_DEPLOY_CONFIG_PATH),
"chown -R 33:33 /etc/ocis",
# oc10 configs
"mkdir -p /etc/templates",
"mkdir -p /etc/pre_server.d",

2
.vscode/launch.json vendored
View File

@@ -41,7 +41,7 @@
// metadata storage
"METADATA_USER_ID": "some-metadata-user-id"
// OCIS_RUN_EXTENSIONS allows to start a subset of extensions even in the supervised mode
//"OCIS_RUN_EXTENSIONS": "settings,storage-metadata,glauth,graph,graph-explorer,idp,ocs,store,thumbnails,web,webdav,storage-frontend,storage-gateway,storage-userprovider,storage-groupprovider,storage-authbasic,storage-authbearer,storage-authmachine,storage-users,storage-shares,storage-public-link,storage-appprovider,storage-sharing,accounts,proxy,ocdav",
//"OCIS_RUN_EXTENSIONS": "settings,storage-metadata,glauth,graph,graph-explorer,idp,ocs,store,thumbnails,web,webdav,frontend,gateway,user,group,auth-basic,auth-bearer,storage-authmachine,storage-users,storage-shares,storage-publiclink,app-provider,sharing,accounts,proxy,ocdav",
}
}
]

View File

@@ -10,9 +10,11 @@ The following sections list the changes for unreleased.
* Bugfix - Return proper errors when ocs/cloud/users is using the cs3 backend: [#3483](https://github.com/owncloud/ocis/issues/3483)
* Bugfix - URL encode the webdav url in the graph API: [#3597](https://github.com/owncloud/ocis/pull/3597)
* Change - Load configuration files just from one directory: [#3587](https://github.com/owncloud/ocis/pull/3587)
* Change - Reduce permissions on docker image predeclared volumes: [#3641](https://github.com/owncloud/ocis/pull/3641)
* Change - Introduce `ocis init` and remove all default secrets: [#3551](https://github.com/owncloud/ocis/pull/3551)
* Change - Reduce drives in graph /me/drives API: [#3629](https://github.com/owncloud/ocis/pull/3629)
* Change - Switched default configuration to use libregraph/idm: [#3331](https://github.com/owncloud/ocis/pull/3331)
* Change - Use new space ID util functions: [#3648](https://github.com/owncloud/ocis/pull/3648)
* Enhancement - Align service naming: [#3606](https://github.com/owncloud/ocis/pull/3606)
* Enhancement - Wrap metadata storage with dedicated reva gateway: [#3602](https://github.com/owncloud/ocis/pull/3602)
* Enhancement - Add initial version of the search extensions: [#3635](https://github.com/owncloud/ocis/pull/3635)
@@ -20,6 +22,7 @@ The following sections list the changes for unreleased.
* Enhancement - Added `share_jail` and `projects` feature flags in spaces capability: [#3626](https://github.com/owncloud/ocis/pull/3626)
* Enhancement - Update linkshare capabilities: [#3579](https://github.com/owncloud/ocis/pull/3579)
* Enhancement - Update reva to v2.x.x: [#3552](https://github.com/owncloud/ocis/pull/3552)
* Enhancement - Update ownCloud Web to v5.5.0-rc.2: [#6854](https://github.com/owncloud/web/pull/6854)
## Details
@@ -58,6 +61,16 @@ The following sections list the changes for unreleased.
https://github.com/owncloud/ocis/pull/3587
* Change - Reduce permissions on docker image predeclared volumes: [#3641](https://github.com/owncloud/ocis/pull/3641)
We've lowered the permissions on the predeclared volumes of the oCIS docker image from 777 to
750.
This change doesn't affect you, unless you use the docker image with the non default uid/guid to
start oCIS (default is 1000:1000).
https://github.com/owncloud/ocis/pull/3641
* Change - Introduce `ocis init` and remove all default secrets: [#3551](https://github.com/owncloud/ocis/pull/3551)
We've removed all default secrets. This means you can't start oCIS any longer without setting
@@ -85,6 +98,13 @@ The following sections list the changes for unreleased.
https://github.com/owncloud/ocis/pull/3331
https://github.com/owncloud/ocis/pull/3633
* Change - Use new space ID util functions: [#3648](https://github.com/owncloud/ocis/pull/3648)
Changed code to use the new space ID util functions so that everything works with the new spaces
ID format.
https://github.com/owncloud/ocis/pull/3648
* Enhancement - Align service naming: [#3606](https://github.com/owncloud/ocis/pull/3606)
We now reflect the configured service names when listing them in the ocis runtime
@@ -148,6 +168,17 @@ The following sections list the changes for unreleased.
https://github.com/owncloud/ocis/pull/3611
https://github.com/owncloud/ocis/pull/3637
https://github.com/owncloud/ocis/pull/3652
* Enhancement - Update ownCloud Web to v5.5.0-rc.2: [#6854](https://github.com/owncloud/web/pull/6854)
Tags: web
We updated ownCloud Web to v5.5.0-rc.2. Please refer to the changelog (linked) for details on
the web release.
https://github.com/owncloud/web/pull/6854
https://github.com/owncloud/ocis/pull/3664
https://github.com/owncloud/web/releases/tag/v5.5.0-rc.2
# Changelog for [1.20.0] (2022-04-13)
The following sections list the changes for 1.20.0.

View File

@@ -17,17 +17,34 @@ L10N_MODULES := $(shell find . -path '*.tx*' -name 'config' | sed 's|/[^/]*$$||'
# if you add a module here please also add it to the .drone.star file
OCIS_MODULES = \
extensions/accounts \
extensions/app-provider \
extensions/app-registry \
extensions/audit \
extensions/auth-basic \
extensions/auth-bearer \
extensions/auth-machine \
extensions/frontend \
extensions/gateway \
extensions/glauth \
extensions/graph \
extensions/graph-explorer \
extensions/group \
extensions/idm \
extensions/idp \
extensions/nats \
extensions/notifications \
extensions/ocdav \
extensions/ocs \
extensions/proxy \
extensions/settings \
extensions/storage \
extensions/sharing \
extensions/storage-metadata \
extensions/storage-publiclink \
extensions/storage-shares \
extensions/storage-users \
extensions/store \
extensions/thumbnails \
extensions/user \
extensions/web \
extensions/webdav\
ocis \
@@ -111,7 +128,7 @@ composer.lock: composer.json
.PHONY: generate
generate:
@for mod in $(OCIS_MODULES); do \
$(MAKE) --no-print-directory -C $$mod generate || exit 1; \
$(MAKE) -C $$mod generate || exit 1; \
done
.PHONY: vet

View File

@@ -0,0 +1,9 @@
Change: Reduce permissions on docker image predeclared volumes
We've lowered the permissions on the predeclared volumes of the oCIS
docker image from 777 to 750.
This change doesn't affect you, unless you use the docker image with
the non default uid/guid to start oCIS (default is 1000:1000).
https://github.com/owncloud/ocis/pull/3641

View File

@@ -0,0 +1,5 @@
Change: Use new space ID util functions
Changed code to use the new space ID util functions so that everything works with the new spaces ID format.
https://github.com/owncloud/ocis/pull/3648

View File

@@ -0,0 +1,9 @@
Enhancement: Update ownCloud Web to v5.5.0-rc.2
Tags: web
We updated ownCloud Web to v5.5.0-rc.2. Please refer to the changelog (linked) for details on the web release.
https://github.com/owncloud/web/pull/6854
https://github.com/owncloud/ocis/pull/3664
https://github.com/owncloud/web/releases/tag/v5.5.0-rc.2

View File

@@ -108,7 +108,7 @@ services:
OCIS_STORAGE_READ_ONLY: "false" # TODO: conflict with OWNCLOUDSQL -> https://github.com/owncloud/ocis/issues/2303
# General oCIS config
# OCIS_RUN_EXTENSIONS specifies to start all extensions except glauth, idp and accounts. These are replaced by external services
OCIS_RUN_EXTENSIONS: settings,storage-metadata,graph,graph-explorer,ocs,store,thumbnails,web,webdav,storage-frontend,storage-gateway,storage-userprovider,storage-groupprovider,storage-authbasic,storage-authbearer,storage-authmachine,storage-users,storage-shares,storage-public-link,storage-appprovider,storage-sharing,proxy,nats
OCIS_RUN_EXTENSIONS: settings,storage-metadata,graph,graph-explorer,ocs,store,thumbnails,web,webdav,storage-frontend,storage-gateway,storage-userprovider,storage-groupprovider,storage-authbasic,storage-authbearer,storage-authmachine,storage-users,storage-shares,storage-public-link,app-provider,storage-sharing,proxy,nats
OCIS_LOG_LEVEL: ${OCIS_LOG_LEVEL:-error} # make oCIS less verbose
OCIS_URL: https://${CLOUD_DOMAIN:-cloud.owncloud.test}
PROXY_TLS: "false" # do not use SSL between Traefik and oCIS

View File

@@ -664,7 +664,8 @@ services:
STORAGE_FRONTEND_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
STORAGE_FRONTEND_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
STORAGE_FRONTEND_APPPROVIDER_INSECURE: "true"
# FIXME this now lives in a dedicated service
APP_PROVIDER_WOPI_INSECURE: "true"
STORAGE_FRONTEND_ARCHIVER_INSECURE: "true"
STORAGE_FRONTEND_OCDAV_INSECURE: "true"

View File

@@ -0,0 +1,16 @@
---
title: App Provider
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/app-provider
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/app-provider
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/app-provider-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/app-provider_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: App Registry
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/app-registry
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -3,7 +3,7 @@ title: "Apps"
date: 2018-05-02T00:00:00+00:00
weight: 10
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage
geekdocEditPath: edit/master/docs/extensions/app-registry
geekdocFilePath: apps.md
---

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/app-registry
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/app-registry-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/app-registry_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: Auth-Basic
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/auth-basic
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/auth-basic
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/auth-basic-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/auth-basic_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: Auth-Bearer
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/auth-bearer
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/auth-bearer
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/auth-bearer-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/auth-bearer_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: Auth-Machine
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/auth-machine
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/auth-machine
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/auth-machine-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/auth-machine_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: Frontend
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/frontend
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/frontend
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/frontend-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/frontend_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: Gateway
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/gateway
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/gateway
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/gateway-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/gateway_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: Group
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/group
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/group
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/group-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/group_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: ocDAV
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/ocdav
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/ocdav
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/ocdav-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/ocdav_configvars.md" >}}

View File

@@ -46,7 +46,7 @@ We also suggest to use the last port in your extensions' range as a debug/metric
| 9225-9229 | photoprism (state: PoC) |
| 9230-9234 | [nats](https://github.com/owncloud/ocis/tree/master/nats) |
| 9235-9239 | idm TBD |
| 9240-9244 | FREE |
| 9240-9244 | [app-registry](https://github.com/owncloud/ocis/tree/master/extensions/app-registry) |
| 9245-9249 | FREE |
| 9250-9254 | oCIS Runtime |
| 9255-9259 | FREE |

View File

@@ -0,0 +1,16 @@
---
title: Metadata Storage
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage-metadata
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage-metadata
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/storage-metadata-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/storage-metadata_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: Publiclink Storage
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage-publiclink
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage-publiclink
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/storage-publiclink-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/storage-publiclink_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: Shares Storage
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage-shares
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage-shares
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/storage-shares-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/storage-shares_configvars.md" >}}

View File

@@ -0,0 +1,16 @@
---
title: Users Storage
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage-users
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/storage-users
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/storage-users-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/storage-users_configvars.md" >}}

View File

@@ -34,8 +34,8 @@ For now, the storage service uses these ports to preconfigure those services:
| 9159 | storage users debug |
| 9160 | groups |
| 9161 | groups debug |
| 9164 | storage appprovider |
| 9165 | storage appprovider debug |
| 9164 | storage app-provider |
| 9165 | storage app-provider debug |
| 9178 | storage public link |
| 9179 | storage public link data |
| 9180 | accounts grpc |

View File

@@ -0,0 +1,16 @@
---
title: User
date: 2022-03-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/user
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
## Table of Contents
{{< toc-tree >}}

View File

@@ -0,0 +1,15 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/extensions/user
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="extensions/_includes/user-config-example.yaml" language="yaml" >}}
{{< include file="extensions/_includes/user_configvars.md" >}}

View File

@@ -13,9 +13,9 @@ import (
)
var targets = map[string]string{
"adoc-generator.go.tmpl": "output/adoc/adoc-generator.go",
"example-config-generator.go.tmpl": "output/exampleconfig/example-config-generator.go",
"extractor.go.tmpl": "output/env/runner.go",
"adoc-generator.go.tmpl": "output/adoc/adoc-generator.go",
"example-config-generator.go.tmpl": "output/exampleconfig/example-config-generator.go",
"environment-variable-docs-generator.go.tmpl": "output/env/environment-variable-docs-generator.go",
}
func main() {

View File

@@ -34,7 +34,7 @@ func GetCommands(cfg *config.Config) cli.Commands {
// Execute is the entry point for the ocis-accounts command.
func Execute(cfg *config.Config) error {
app := clihelper.DefaultApp(&cli.App{
Name: "ocis-accounts",
Name: "accounts",
Usage: "Provide accounts and groups for oCIS",
Commands: GetCommands(cfg),
})

View File

@@ -0,0 +1,37 @@
SHELL := bash
NAME := app-provider
include ../../.make/recursion.mk
############ tooling ############
ifneq (, $(shell which go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
include ../../.bingo/Variables.mk
endif
############ go tooling ############
include ../../.make/go.mk
############ release ############
include ../../.make/release.mk
############ docs generate ############
include ../../.make/docs.mk
.PHONY: docs-generate
docs-generate: config-docs-generate
############ generate ############
include ../../.make/generate.mk
.PHONY: ci-go-generate
ci-go-generate: # CI runs ci-node-generate automatically before this target
.PHONY: ci-node-generate
ci-node-generate:
############ licenses ############
.PHONY: ci-node-check-licenses
ci-node-check-licenses:
.PHONY: ci-node-save-licenses
ci-node-save-licenses:

View File

@@ -0,0 +1,14 @@
package main
import (
"os"
"github.com/owncloud/ocis/extensions/app-provider/pkg/command"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config/defaults"
)
func main() {
if err := command.Execute(defaults.DefaultConfig()); err != nil {
os.Exit(1)
}
}

View File

@@ -0,0 +1,57 @@
package command
import (
"fmt"
"net/http"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config/parser"
"github.com/owncloud/ocis/extensions/app-provider/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
"http://%s/healthz",
cfg.Debug.Addr,
),
)
if err != nil {
logger.Fatal().
Err(err).
Msg("Failed to request health check")
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")
}
logger.Debug().
Int("code", resp.StatusCode).
Msg("Health got a good state")
return nil
},
}
}

View File

@@ -0,0 +1,64 @@
package command
import (
"context"
"os"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocis-accounts command.
func Execute(cfg *config.Config) error {
app := clihelper.DefaultApp(&cli.App{
Name: "app-provider",
Usage: "Provide apps for oCIS",
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
return app.Run(os.Args)
}
// SutureService allows for the accounts command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config
}
// NewSutureService creates a new accounts.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
cfg.AppProvider.Commons = cfg.Commons
return SutureService{
cfg: cfg.AppProvider,
}
}
func (s SutureService) Serve(ctx context.Context) error {
s.cfg.Context = ctx
if err := Execute(s.cfg); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,107 @@
package command
import (
"context"
"fmt"
"os"
"path"
"github.com/cs3org/reva/v2/cmd/revad/runtime"
"github.com/gofrs/uuid"
"github.com/oklog/run"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config/parser"
"github.com/owncloud/ocis/extensions/app-provider/pkg/logging"
"github.com/owncloud/ocis/extensions/app-provider/pkg/revaconfig"
"github.com/owncloud/ocis/extensions/app-provider/pkg/server/debug"
"github.com/owncloud/ocis/extensions/app-provider/pkg/tracing"
"github.com/owncloud/ocis/ocis-pkg/service/external"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entry point for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg, logger)
if err != nil {
return err
}
gr := run.Group{}
ctx, cancel := defineContext(cfg)
defer cancel()
pidFile := path.Join(os.TempDir(), "revad-"+cfg.Service.Name+"-"+uuid.Must(uuid.NewV4()).String()+".pid")
rcfg := revaconfig.AppProviderConfigFromStruct(cfg)
gr.Add(func() error {
runtime.RunWithOptions(rcfg, pidFile, runtime.WithLogger(&logger.Logger))
return nil
}, func(_ error) {
logger.Info().
Str("server", cfg.Service.Name).
Msg("Shutting down server")
cancel()
})
debugServer, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
cancel()
})
if !cfg.Supervised {
sync.Trap(&gr, cancel)
}
if err := external.RegisterGRPCEndpoint(
ctx,
cfg.GRPC.Namespace+"."+cfg.Service.Name,
uuid.Must(uuid.NewV4()).String(),
cfg.GRPC.Addr,
version.String,
logger,
); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc endpoint")
}
return gr.Run()
},
}
}
// defineContext sets the context for the extension. If there is a context configured it will create a new child from it,
// if not, it will create a root context that can be cancelled.
func defineContext(cfg *config.Config) (context.Context, context.CancelFunc) {
return func() (context.Context, context.CancelFunc) {
if cfg.Context == nil {
return context.WithCancel(context.Background())
}
return context.WithCancel(cfg.Context)
}()
}

View File

@@ -0,0 +1,50 @@
package command
import (
"fmt"
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/urfave/cli/v2"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.GRPC.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}
table := tw.NewWriter(os.Stdout)
table.SetHeader([]string{"Version", "Address", "Id"})
table.SetAutoFormatHeaders(false)
for _, s := range services {
for _, n := range s.Nodes {
table.Append([]string{s.Version, n.Address, n.Id})
}
}
table.Render()
return nil
},
}
}

View File

@@ -0,0 +1,74 @@
package config
import (
"context"
"github.com/owncloud/ocis/ocis-pkg/shared"
)
type Config struct {
*shared.Commons `yaml:"-"`
Service Service `yaml:"-"`
Tracing *Tracing `yaml:"tracing"`
Log *Log `yaml:"log"`
Debug Debug `yaml:"debug"`
GRPC GRPCConfig `yaml:"grpc"`
TokenManager *TokenManager `yaml:"token_manager"`
Reva *Reva `yaml:"reva"`
ExternalAddr string `yaml:"external_addr"`
Driver string `yaml:"driver"`
Drivers Drivers `yaml:"drivers"`
Supervised bool `yaml:"-"`
Context context.Context `yaml:"-"`
}
type Tracing struct {
Enabled bool `yaml:"enabled" env:"OCIS_TRACING_ENABLED;APP_PROVIDER_TRACING_ENABLED" desc:"Activates tracing."`
Type string `yaml:"type" env:"OCIS_TRACING_TYPE;APP_PROVIDER_TRACING_TYPE"`
Endpoint string `yaml:"endpoint" env:"OCIS_TRACING_ENDPOINT;APP_PROVIDER_TRACING_ENDPOINT" desc:"The endpoint to the tracing collector."`
Collector string `yaml:"collector" env:"OCIS_TRACING_COLLECTOR;APP_PROVIDER_TRACING_COLLECTOR"`
}
type Log struct {
Level string `yaml:"level" env:"OCIS_LOG_LEVEL;APP_PROVIDER_LOG_LEVEL" desc:"The log level."`
Pretty bool `yaml:"pretty" env:"OCIS_LOG_PRETTY;APP_PROVIDER_LOG_PRETTY" desc:"Activates pretty log output."`
Color bool `yaml:"color" env:"OCIS_LOG_COLOR;APP_PROVIDER_LOG_COLOR" desc:"Activates colorized log output."`
File string `yaml:"file" env:"OCIS_LOG_FILE;APP_PROVIDER_LOG_FILE" desc:"The target log file."`
}
type Service struct {
Name string `yaml:"-"`
}
type Debug struct {
Addr string `yaml:"addr" env:"APP_PROVIDER_DEBUG_ADDR"`
Token string `yaml:"token" env:"APP_PROVIDER_DEBUG_TOKEN"`
Pprof bool `yaml:"pprof" env:"APP_PROVIDER_DEBUG_PPROF"`
Zpages bool `yaml:"zpages" env:"APP_PROVIDER_DEBUG_ZPAGES"`
}
type GRPCConfig struct {
Addr string `yaml:"addr" env:"APP_PROVIDER_GRPC_ADDR" desc:"The address of the grpc service."`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"APP_PROVIDER_GRPC_PROTOCOL" desc:"The transport protocol of the grpc service."`
}
type Drivers struct {
WOPI WOPIDriver `yaml:"wopi" desc:"driver for the CS3org WOPI server"`
}
type WOPIDriver struct {
AppAPIKey string `yaml:"app_api_key" env:"APP_PROVIDER_WOPI_APP_API_KEY" desc:"api key for the wopi app"`
AppDesktopOnly bool `yaml:"app_desktop_only" env:"APP_PROVIDER_WOPI_APP_DESKTOP_ONLY" desc:"offer this app only on desktop"`
AppIconURI string `yaml:"app_icon_uri" env:"APP_PROVIDER_WOPI_APP_ICON_URI" desc:"uri to an app icon to be used by clients"`
AppInternalURL string `yaml:"app_internal_url" env:"APP_PROVIDER_WOPI_APP_INTERNAL_URL" desc:"internal url to the app, eg in your DMZ"`
AppName string `yaml:"app_name" env:"APP_PROVIDER_WOPI_APP_NAME" desc:"human readable app name"`
AppURL string `yaml:"app_url" env:"APP_PROVIDER_WOPI_APP_URL" desc:"url for end users to access the app"`
Insecure bool `yaml:"insecure" env:"APP_PROVIDER_WOPI_INSECURE" desc:"allow insecure connections to the app"`
IopSecret string `yaml:"wopi_server_iop_secret" env:"APP_PROVIDER_WOPI_WOPI_SERVER_IOP_SECRET" desc:"shared secret of the CS3org WOPI server"`
WopiURL string `yaml:"wopi_server_external_url" env:"APP_PROVIDER_WOPI_WOPI_SERVER_EXTERNAL_URL" desc:"external url of the CS3org WOPI server"`
}

View File

@@ -1,7 +1,7 @@
package defaults
import (
"github.com/owncloud/ocis/extensions/appprovider/pkg/config"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/shared"
)
@@ -21,11 +21,12 @@ func DefaultConfig() *config.Config {
Zpages: false,
},
GRPC: config.GRPCConfig{
Addr: "127.0.0.1:9164",
Protocol: "tcp",
Addr: "127.0.0.1:9164",
Namespace: "com.owncloud.api",
Protocol: "tcp",
},
Service: config.Service{
Name: "appprovider",
Name: "app-provider",
},
Reva: &config.Reva{
Address: "127.0.0.1:9142",
@@ -39,15 +40,15 @@ func DefaultConfig() *config.Config {
func EnsureDefaults(cfg *config.Config) {
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Logging == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Logging = &config.Logging{
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &config.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Logging == nil {
cfg.Logging = &config.Logging{}
} else if cfg.Log == nil {
cfg.Log = &config.Log{}
}
// provide with defaults for shared tracing, since we need a valid destination address for BindEnv.
if cfg.Tracing == nil && cfg.Commons != nil && cfg.Commons.Tracing != nil {

View File

@@ -3,8 +3,8 @@ package parser
import (
"errors"
"github.com/owncloud/ocis/extensions/appprovider/pkg/config"
"github.com/owncloud/ocis/extensions/appprovider/pkg/config/defaults"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config/defaults"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/shared"

View File

@@ -0,0 +1,17 @@
package logging
import (
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// LoggerFromConfig initializes a service-specific logger instance.
func Configure(name string, cfg *config.Log) log.Logger {
return log.NewLogger(
log.Name(name),
log.Level(cfg.Level),
log.Pretty(cfg.Pretty),
log.Color(cfg.Color),
log.File(cfg.File),
)
}

View File

@@ -0,0 +1,47 @@
package revaconfig
import (
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
)
// AppProviderConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
func AppProviderConfigFromStruct(cfg *config.Config) map[string]interface{} {
rcfg := map[string]interface{}{
"core": map[string]interface{}{
"tracing_enabled": cfg.Tracing.Enabled,
"tracing_endpoint": cfg.Tracing.Endpoint,
"tracing_collector": cfg.Tracing.Collector,
"tracing_service_name": cfg.Service.Name,
},
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,
"address": cfg.GRPC.Addr,
"services": map[string]interface{}{
"appprovider": map[string]interface{}{
"app_provider_url": cfg.ExternalAddr,
"driver": cfg.Driver,
"drivers": map[string]interface{}{
"wopi": map[string]interface{}{
"app_api_key": cfg.Drivers.WOPI.AppAPIKey,
"app_desktop_only": cfg.Drivers.WOPI.AppDesktopOnly,
"app_icon_uri": cfg.Drivers.WOPI.AppIconURI,
"app_int_url": cfg.Drivers.WOPI.AppInternalURL,
"app_name": cfg.Drivers.WOPI.AppName,
"app_url": cfg.Drivers.WOPI.AppURL,
"insecure_connections": cfg.Drivers.WOPI.Insecure,
"iop_secret": cfg.Drivers.WOPI.IopSecret,
"jwt_secret": cfg.TokenManager.JWTSecret,
"wopi_url": cfg.Drivers.WOPI.WopiURL,
},
},
},
},
},
}
return rcfg
}

View File

@@ -0,0 +1,50 @@
package debug
import (
"context"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Context context.Context
Config *config.Config
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Context provides a function to set the context option.
func Context(val context.Context) Option {
return func(o *Options) {
o.Context = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}

View File

@@ -0,0 +1,63 @@
package debug
import (
"io"
"net/http"
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/service/debug"
"github.com/owncloud/ocis/ocis-pkg/version"
)
// Server initializes the debug service and server.
func Server(opts ...Option) (*http.Server, error) {
options := newOptions(opts...)
return debug.NewService(
debug.Logger(options.Logger),
debug.Name(options.Config.Service.Name),
debug.Version(version.String),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),
debug.Pprof(options.Config.Debug.Pprof),
debug.Zpages(options.Config.Debug.Zpages),
debug.Health(health(options.Config)),
debug.Ready(ready(options.Config)),
//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
), nil
}
// health implements the health check.
func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}
// ready implements the ready check.
func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}

View File

@@ -0,0 +1,18 @@
package tracing
import (
"github.com/owncloud/ocis/extensions/app-provider/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/tracing"
"go.opentelemetry.io/otel/trace"
)
var (
// TraceProvider is the global trace provider for the service.
TraceProvider = trace.NewNoopTracerProvider()
)
func Configure(cfg *config.Config, logger log.Logger) error {
tracing.Configure(cfg.Tracing.Enabled, cfg.Tracing.Type, logger)
return nil
}

View File

@@ -0,0 +1,37 @@
SHELL := bash
NAME := app-registry
include ../../.make/recursion.mk
############ tooling ############
ifneq (, $(shell which go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
include ../../.bingo/Variables.mk
endif
############ go tooling ############
include ../../.make/go.mk
############ release ############
include ../../.make/release.mk
############ docs generate ############
include ../../.make/docs.mk
.PHONY: docs-generate
docs-generate: config-docs-generate
############ generate ############
include ../../.make/generate.mk
.PHONY: ci-go-generate
ci-go-generate: # CI runs ci-node-generate automatically before this target
.PHONY: ci-node-generate
ci-node-generate:
############ licenses ############
.PHONY: ci-node-check-licenses
ci-node-check-licenses:
.PHONY: ci-node-save-licenses
ci-node-save-licenses:

View File

@@ -0,0 +1,14 @@
package main
import (
"os"
"github.com/owncloud/ocis/extensions/app-registry/pkg/command"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config/defaults"
)
func main() {
if err := command.Execute(defaults.DefaultConfig()); err != nil {
os.Exit(1)
}
}

View File

@@ -0,0 +1,57 @@
package command
import (
"fmt"
"net/http"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config/parser"
"github.com/owncloud/ocis/extensions/app-registry/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
"http://%s/healthz",
cfg.Debug.Addr,
),
)
if err != nil {
logger.Fatal().
Err(err).
Msg("Failed to request health check")
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")
}
logger.Debug().
Int("code", resp.StatusCode).
Msg("Health got a good state")
return nil
},
}
}

View File

@@ -0,0 +1,64 @@
package command
import (
"context"
"os"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocis-app-registry command.
func Execute(cfg *config.Config) error {
app := clihelper.DefaultApp(&cli.App{
Name: "app-registry",
Usage: "Provide a app registry for oCIS",
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
return app.Run(os.Args)
}
// SutureService allows for the app-registry command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config
}
// NewSutureService creates a new app-registry.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
cfg.AppRegistry.Commons = cfg.Commons
return SutureService{
cfg: cfg.AppRegistry,
}
}
func (s SutureService) Serve(ctx context.Context) error {
s.cfg.Context = ctx
if err := Execute(s.cfg); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,102 @@
package command
import (
"context"
"fmt"
"os"
"path"
"github.com/cs3org/reva/v2/cmd/revad/runtime"
"github.com/gofrs/uuid"
"github.com/oklog/run"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config/parser"
"github.com/owncloud/ocis/extensions/app-registry/pkg/logging"
"github.com/owncloud/ocis/extensions/app-registry/pkg/revaconfig"
"github.com/owncloud/ocis/extensions/app-registry/pkg/server/debug"
"github.com/owncloud/ocis/extensions/app-registry/pkg/tracing"
"github.com/owncloud/ocis/ocis-pkg/service/external"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entry point for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg, logger)
if err != nil {
return err
}
gr := run.Group{}
ctx, cancel := defineContext(cfg)
defer cancel()
pidFile := path.Join(os.TempDir(), "revad-"+cfg.Service.Name+"-"+uuid.Must(uuid.NewV4()).String()+".pid")
rcfg := revaconfig.AppRegistryConfigFromStruct(cfg, logger)
gr.Add(func() error {
runtime.RunWithOptions(rcfg, pidFile, runtime.WithLogger(&logger.Logger))
return nil
}, func(_ error) {
logger.Info().
Str("server", cfg.Service.Name).
Msg("Shutting down server")
cancel()
})
debugServer, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
cancel()
})
if err := external.RegisterGRPCEndpoint(
ctx,
cfg.GRPC.Namespace+"."+cfg.Service.Name,
uuid.Must(uuid.NewV4()).String(),
cfg.GRPC.Addr,
version.String,
logger,
); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc endpoint")
}
return gr.Run()
},
}
}
// defineContext sets the context for the extension. If there is a context configured it will create a new child from it,
// if not, it will create a root context that can be cancelled.
func defineContext(cfg *config.Config) (context.Context, context.CancelFunc) {
return func() (context.Context, context.CancelFunc) {
if cfg.Context == nil {
return context.WithCancel(context.Background())
}
return context.WithCancel(cfg.Context)
}()
}

View File

@@ -0,0 +1,50 @@
package command
import (
"fmt"
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
"github.com/urfave/cli/v2"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.GRPC.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}
table := tw.NewWriter(os.Stdout)
table.SetHeader([]string{"Version", "Address", "Id"})
table.SetAutoFormatHeaders(false)
for _, s := range services {
for _, n := range s.Nodes {
table.Append([]string{s.Version, n.Address, n.Id})
}
}
table.Render()
return nil
},
}
}

View File

@@ -0,0 +1,70 @@
package config
import (
"context"
"github.com/owncloud/ocis/ocis-pkg/shared"
)
type Config struct {
*shared.Commons `yaml:"-"`
Service Service `yaml:"-"`
Tracing *Tracing `yaml:"tracing"`
Log *Log `yaml:"log"`
Debug Debug `yaml:"debug"`
GRPC GRPCConfig `yaml:"grpc"`
TokenManager *TokenManager `yaml:"token_manager"`
Reva *Reva `yaml:"reva"`
AppRegistry AppRegistry `yaml:"app_registry"`
Supervised bool `yaml:"-"`
Context context.Context `yaml:"-"`
}
type Tracing struct {
Enabled bool `yaml:"enabled" env:"OCIS_TRACING_ENABLED;APP_REGISTRY_TRACING_ENABLED" desc:"Activates tracing."`
Type string `yaml:"type" env:"OCIS_TRACING_TYPE;APP_REGISTRY_TRACING_TYPE"`
Endpoint string `yaml:"endpoint" env:"OCIS_TRACING_ENDPOINT;APP_REGISTRY_TRACING_ENDPOINT" desc:"The endpoint to the tracing collector."`
Collector string `yaml:"collector" env:"OCIS_TRACING_COLLECTOR;APP_REGISTRY_TRACING_COLLECTOR"`
}
type Log struct {
Level string `yaml:"level" env:"OCIS_LOG_LEVEL;APP_REGISTRY_LOG_LEVEL" desc:"The log level."`
Pretty bool `yaml:"pretty" env:"OCIS_LOG_PRETTY;APP_REGISTRY_LOG_PRETTY" desc:"Activates pretty log output."`
Color bool `yaml:"color" env:"OCIS_LOG_COLOR;APP_REGISTRY_LOG_COLOR" desc:"Activates colorized log output."`
File string `yaml:"file" env:"OCIS_LOG_FILE;APP_REGISTRY_LOG_FILE" desc:"The target log file."`
}
type Service struct {
Name string `yaml:"-"`
}
type Debug struct {
Addr string `yaml:"addr" env:"APP_REGISTRY_DEBUG_ADDR"`
Token string `yaml:"token" env:"APP_REGISTRY_DEBUG_TOKEN"`
Pprof bool `yaml:"pprof" env:"APP_REGISTRY_DEBUG_PPROF"`
Zpages bool `yaml:"zpages" env:"APP_REGISTRY_DEBUG_ZPAGES"`
}
type GRPCConfig struct {
Addr string `yaml:"addr" env:"APP_REGISTRY_GRPC_ADDR" desc:"The address of the grpc service."`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"APP_REGISTRY_GRPC_PROTOCOL" desc:"The transport protocol of the grpc service."`
}
type AppRegistry struct {
MimeTypeConfig []MimeTypeConfig `yaml:"mimetypes"`
}
type MimeTypeConfig struct {
MimeType string `yaml:"mime_type" mapstructure:"mime_type"`
Extension string `yaml:"extension" mapstructure:"extension"`
Name string `yaml:"name" mapstructure:"name"`
Description string `yaml:"description" mapstructure:"description"`
Icon string `yaml:"icon" mapstructure:"icon"`
DefaultApp string `yaml:"default_app" mapstructure:"default_app"`
AllowCreation bool `yaml:"allow_creation" mapstructure:"allow_creation"`
}

View File

@@ -0,0 +1,155 @@
package defaults
import (
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
)
func FullDefaultConfig() *config.Config {
cfg := DefaultConfig()
EnsureDefaults(cfg)
Sanitize(cfg)
return cfg
}
func DefaultConfig() *config.Config {
return &config.Config{
Debug: config.Debug{
Addr: "127.0.0.1:9243",
Token: "",
Pprof: false,
Zpages: false,
},
GRPC: config.GRPCConfig{
Addr: "127.0.0.1:9242",
Namespace: "com.owncloud.api",
Protocol: "tcp",
},
Service: config.Service{
Name: "app-registry",
},
Reva: &config.Reva{
Address: "127.0.0.1:9142",
},
AppRegistry: config.AppRegistry{
MimeTypeConfig: defaultMimeTypeConfig(),
},
}
}
func defaultMimeTypeConfig() []config.MimeTypeConfig {
return []config.MimeTypeConfig{
{
MimeType: "application/pdf",
Extension: "pdf",
Name: "PDF",
Description: "PDF document",
},
{
MimeType: "application/vnd.oasis.opendocument.text",
Extension: "odt",
Name: "OpenDocument",
Description: "OpenDocument text document",
AllowCreation: true,
},
{
MimeType: "application/vnd.oasis.opendocument.spreadsheet",
Extension: "ods",
Name: "OpenSpreadsheet",
Description: "OpenDocument spreadsheet document",
AllowCreation: true,
},
{
MimeType: "application/vnd.oasis.opendocument.presentation",
Extension: "odp",
Name: "OpenPresentation",
Description: "OpenDocument presentation document",
AllowCreation: true,
},
{
MimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
Extension: "docx",
Name: "Microsoft Word",
Description: "Microsoft Word document",
AllowCreation: true,
},
{
MimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
Extension: "xlsx",
Name: "Microsoft Excel",
Description: "Microsoft Excel document",
AllowCreation: true,
},
{
MimeType: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
Extension: "pptx",
Name: "Microsoft PowerPoint",
Description: "Microsoft PowerPoint document",
AllowCreation: true,
},
{
MimeType: "application/vnd.jupyter",
Extension: "ipynb",
Name: "Jupyter Notebook",
Description: "Jupyter Notebook",
},
{
MimeType: "text/markdown",
Extension: "md",
Name: "Markdown file",
Description: "Markdown file",
AllowCreation: true,
},
{
MimeType: "application/compressed-markdown",
Extension: "zmd",
Name: "Compressed markdown file",
Description: "Compressed markdown file",
},
}
}
func EnsureDefaults(cfg *config.Config) {
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &config.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil {
cfg.Log = &config.Log{}
}
// provide with defaults for shared tracing, since we need a valid destination address for BindEnv.
if cfg.Tracing == nil && cfg.Commons != nil && cfg.Commons.Tracing != nil {
cfg.Tracing = &config.Tracing{
Enabled: cfg.Commons.Tracing.Enabled,
Type: cfg.Commons.Tracing.Type,
Endpoint: cfg.Commons.Tracing.Endpoint,
Collector: cfg.Commons.Tracing.Collector,
}
} else if cfg.Tracing == nil {
cfg.Tracing = &config.Tracing{}
}
if cfg.Reva == nil && cfg.Commons != nil && cfg.Commons.Reva != nil {
cfg.Reva = &config.Reva{
Address: cfg.Commons.Reva.Address,
}
} else if cfg.Reva == nil {
cfg.Reva = &config.Reva{}
}
if cfg.TokenManager == nil && cfg.Commons != nil && cfg.Commons.TokenManager != nil {
cfg.TokenManager = &config.TokenManager{
JWTSecret: cfg.Commons.TokenManager.JWTSecret,
}
} else if cfg.TokenManager == nil {
cfg.TokenManager = &config.TokenManager{}
}
}
func Sanitize(cfg *config.Config) {
// nothing to sanitize here atm
}

View File

@@ -3,9 +3,10 @@ package parser
import (
"errors"
"github.com/owncloud/ocis/extensions/storage-metadata/pkg/config"
"github.com/owncloud/ocis/extensions/storage-metadata/pkg/config/defaults"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config/defaults"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/owncloud/ocis/ocis-pkg/config/envdecode"
)
@@ -33,5 +34,13 @@ func ParseConfig(cfg *config.Config) error {
}
func Validate(cfg *config.Config) error {
if cfg.TokenManager.JWTSecret == "" {
return shared.MissingJWTTokenError(cfg.Service.Name)
}
if cfg.TransferSecret == "" {
return shared.MissingRevaTransferSecretError(cfg.Service.Name)
}
return nil
}

View File

@@ -0,0 +1,11 @@
package config
// Reva defines all available REVA configuration.
type Reva struct {
Address string `yaml:"address" env:"REVA_GATEWAY"`
}
// TokenManager is the config for using the reva token manager
type TokenManager struct {
JWTSecret string `yaml:"jwt_secret" env:"OCIS_JWT_SECRET;APP_REGISTRY_JWT_SECRET"`
}

View File

@@ -0,0 +1,17 @@
package logging
import (
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// LoggerFromConfig initializes a service-specific logger instance.
func Configure(name string, cfg *config.Log) log.Logger {
return log.NewLogger(
log.Name(name),
log.Level(cfg.Level),
log.Pretty(cfg.Pretty),
log.Color(cfg.Color),
log.File(cfg.File),
)
}

View File

@@ -0,0 +1,48 @@
package revaconfig
import (
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/mitchellh/mapstructure"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
)
// AppRegistryConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
func AppRegistryConfigFromStruct(cfg *config.Config, logger log.Logger) map[string]interface{} {
rcfg := map[string]interface{}{
"core": map[string]interface{}{
"tracing_enabled": cfg.Tracing.Enabled,
"tracing_endpoint": cfg.Tracing.Endpoint,
"tracing_collector": cfg.Tracing.Collector,
"tracing_service_name": cfg.Service.Name,
},
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,
"address": cfg.GRPC.Addr,
"services": map[string]interface{}{
"appregistry": map[string]interface{}{
"driver": "static",
"drivers": map[string]interface{}{
"static": map[string]interface{}{
"mime_types": mimetypes(cfg, logger),
},
},
},
},
},
}
return rcfg
}
func mimetypes(cfg *config.Config, logger log.Logger) []map[string]interface{} {
var m []map[string]interface{}
if err := mapstructure.Decode(cfg.AppRegistry.MimeTypeConfig, &m); err != nil {
logger.Error().Err(err).Msg("Failed to decode appregistry mimetypes to mapstructure")
return nil
}
return m
}

View File

@@ -0,0 +1,50 @@
package debug
import (
"context"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Context context.Context
Config *config.Config
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Context provides a function to set the context option.
func Context(val context.Context) Option {
return func(o *Options) {
o.Context = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}

View File

@@ -0,0 +1,63 @@
package debug
import (
"io"
"net/http"
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/service/debug"
"github.com/owncloud/ocis/ocis-pkg/version"
)
// Server initializes the debug service and server.
func Server(opts ...Option) (*http.Server, error) {
options := newOptions(opts...)
return debug.NewService(
debug.Logger(options.Logger),
debug.Name(options.Config.Service.Name),
debug.Version(version.String),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),
debug.Pprof(options.Config.Debug.Pprof),
debug.Zpages(options.Config.Debug.Zpages),
debug.Health(health(options.Config)),
debug.Ready(ready(options.Config)),
//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
), nil
}
// health implements the health check.
func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}
// ready implements the ready check.
func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}

View File

@@ -0,0 +1,18 @@
package tracing
import (
"github.com/owncloud/ocis/extensions/app-registry/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/tracing"
"go.opentelemetry.io/otel/trace"
)
var (
// TraceProvider is the global trace provider for the service.
TraceProvider = trace.NewNoopTracerProvider()
)
func Configure(cfg *config.Config, logger log.Logger) error {
tracing.Configure(cfg.Tracing.Enabled, cfg.Tracing.Type, logger)
return nil
}

View File

@@ -1,170 +0,0 @@
package command
import (
"context"
"flag"
"fmt"
"os"
"path"
"github.com/cs3org/reva/v2/cmd/revad/runtime"
"github.com/gofrs/uuid"
"github.com/oklog/run"
"github.com/owncloud/ocis/extensions/appprovider/pkg/config"
"github.com/owncloud/ocis/extensions/appprovider/pkg/config/parser"
"github.com/owncloud/ocis/extensions/storage/pkg/server/debug"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/owncloud/ocis/ocis-pkg/tracing"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// AppProvider is the entrypoint for the app provider command.
func AppProvider(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "app-provider",
Usage: "start appprovider for providing apps",
Before: func(ctx *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logCfg := cfg.Logging
logger := log.NewLogger(
log.Level(logCfg.Level),
log.File(logCfg.File),
log.Pretty(logCfg.Pretty),
log.Color(logCfg.Color),
)
tracing.Configure(cfg.Tracing.Enabled, cfg.Tracing.Type, logger)
gr := run.Group{}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
uuid := uuid.Must(uuid.NewV4())
pidFile := path.Join(os.TempDir(), "revad-"+c.Command.Name+"-"+uuid.String()+".pid")
rcfg := appProviderConfigFromStruct(c, cfg)
gr.Add(func() error {
runtime.RunWithOptions(rcfg, pidFile, runtime.WithLogger(&logger.Logger))
return nil
}, func(_ error) {
logger.Info().
Str("server", c.Command.Name).
Msg("Shutting down server")
cancel()
})
debugServer, err := debug.Server(
debug.Name(c.Command.Name+"-debug"),
debug.Addr(cfg.Debug.Addr),
debug.Logger(logger),
debug.Context(ctx),
debug.Pprof(cfg.Debug.Pprof),
debug.Zpages(cfg.Debug.Zpages),
debug.Token(cfg.Debug.Token),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
cancel()
})
if !cfg.Supervised {
sync.Trap(&gr, cancel)
}
return gr.Run()
},
}
}
// appProviderConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
func appProviderConfigFromStruct(c *cli.Context, cfg *config.Config) map[string]interface{} {
rcfg := map[string]interface{}{
"core": map[string]interface{}{
"tracing_enabled": cfg.Tracing.Enabled,
"tracing_endpoint": cfg.Tracing.Endpoint,
"tracing_collector": cfg.Tracing.Collector,
"tracing_service_name": c.Command.Name,
},
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,
"address": cfg.GRPC.Addr,
// TODO build services dynamically
"services": map[string]interface{}{
"appprovider": map[string]interface{}{
"app_provider_url": cfg.ExternalAddr,
"driver": cfg.Driver,
"drivers": map[string]interface{}{
"wopi": map[string]interface{}{
"app_api_key": cfg.Drivers.WOPI.AppAPIKey,
"app_desktop_only": cfg.Drivers.WOPI.AppDesktopOnly,
"app_icon_uri": cfg.Drivers.WOPI.AppIconURI,
"app_int_url": cfg.Drivers.WOPI.AppInternalURL,
"app_name": cfg.Drivers.WOPI.AppName,
"app_url": cfg.Drivers.WOPI.AppURL,
"insecure_connections": cfg.Drivers.WOPI.Insecure,
"iop_secret": cfg.Drivers.WOPI.IopSecret,
"jwt_secret": cfg.TokenManager.JWTSecret,
"wopi_url": cfg.Drivers.WOPI.WopiURL,
},
},
},
},
},
}
return rcfg
}
// AppProviderSutureService allows for the app-provider command to be embedded and supervised by a suture supervisor tree.
type AppProviderSutureService struct {
cfg *config.Config
}
// NewAppProvider creates a new store.AppProviderSutureService
func NewAppProvider(cfg *ociscfg.Config) suture.Service {
cfg.AppProvider.Commons = cfg.Commons
return AppProviderSutureService{
cfg: cfg.AppProvider,
}
}
func (s AppProviderSutureService) Serve(ctx context.Context) error {
cmd := AppProvider(s.cfg)
f := &flag.FlagSet{}
cmdFlags := cmd.Flags
for k := range cmdFlags {
if err := cmdFlags[k].Apply(f); err != nil {
return err
}
}
cliCtx := cli.NewContext(nil, f, nil)
if cmd.Before != nil {
if err := cmd.Before(cliCtx); err != nil {
return err
}
}
if err := cmd.Action(cliCtx); err != nil {
return err
}
return nil
}

View File

@@ -1,68 +0,0 @@
package config
import "github.com/owncloud/ocis/ocis-pkg/shared"
type Config struct {
*shared.Commons `yaml:"-"`
Service Service `yaml:"-"`
Tracing *Tracing `yaml:"tracing"`
Logging *Logging `yaml:"log"`
Debug Debug `yaml:"debug"`
Supervised bool `yaml:"-"`
GRPC GRPCConfig `yaml:"grpc"`
TokenManager *TokenManager `yaml:"token_manager"`
Reva *Reva `yaml:"reva"`
SkipUserGroupsInToken bool `yaml:"skip_user_groups_in_token"`
ExternalAddr string `yaml:"external_addr"`
Driver string `yaml:"driver"`
Drivers Drivers `yaml:"drivers"`
}
type Tracing struct {
Enabled bool `yaml:"enabled" env:"OCIS_TRACING_ENABLED;APP_PROVIDER_TRACING_ENABLED" desc:"Activates tracing."`
Type string `yaml:"type" env:"OCIS_TRACING_TYPE;APP_PROVIDER_TRACING_TYPE"`
Endpoint string `yaml:"endpoint" env:"OCIS_TRACING_ENDPOINT;APP_PROVIDER_TRACING_ENDPOINT" desc:"The endpoint to the tracing collector."`
Collector string `yaml:"collector" env:"OCIS_TRACING_COLLECTOR;APP_PROVIDER_TRACING_COLLECTOR"`
}
type Logging struct {
Level string `yaml:"level" env:"OCIS_LOG_LEVEL;APP_PROVIDER_LOG_LEVEL" desc:"The log level."`
Pretty bool `yaml:"pretty" env:"OCIS_LOG_PRETTY;APP_PROVIDER_LOG_PRETTY" desc:"Activates pretty log output."`
Color bool `yaml:"color" env:"OCIS_LOG_COLOR;APP_PROVIDER_LOG_COLOR" desc:"Activates colorized log output."`
File string `yaml:"file" env:"OCIS_LOG_FILE;APP_PROVIDER_LOG_FILE" desc:"The target log file."`
}
type Service struct {
Name string `yaml:"-"`
}
type Debug struct {
Addr string `yaml:"addr" env:"APP_PROVIDER_DEBUG_ADDR"`
Token string `yaml:"token" env:"APP_PROVIDER_DEBUG_TOKEN"`
Pprof bool `yaml:"pprof" env:"APP_PROVIDER_DEBUG_PPROF"`
Zpages bool `yaml:"zpages" env:"APP_PROVIDER_DEBUG_ZPAGES"`
}
type GRPCConfig struct {
Addr string `yaml:"addr" env:"APP_PROVIDER_GRPC_ADDR" desc:"The address of the grpc service."`
Protocol string `yaml:"protocol" env:"APP_PROVIDER_GRPC_PROTOCOL" desc:"The transport protocol of the grpc service."`
}
type Drivers struct {
WOPI WOPIDriver
}
type WOPIDriver struct {
AppAPIKey string `yaml:"app_api_key"`
AppDesktopOnly bool `yaml:"app_desktop_only"`
AppIconURI string `yaml:"app_icon_uri"`
AppInternalURL string `yaml:"app_internal_url"`
AppName string `yaml:"app_name"`
AppURL string `yaml:"app_url"`
Insecure bool `yaml:"insecure"`
IopSecret string `yaml:"ipo_secret"`
WopiURL string `yaml:"wopi_url"`
}

View File

@@ -48,7 +48,7 @@ type SutureService struct {
// NewSutureService creates a new audit.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
cfg.Settings.Commons = cfg.Commons
cfg.Audit.Commons = cfg.Commons
return SutureService{
cfg: cfg.Audit,
}

View File

@@ -23,9 +23,9 @@ type Config struct {
// Events combines the configuration options for the event bus.
type Events struct {
Endpoint string `yaml:"events_endpoint" env:"AUDIT_EVENTS_ENDPOINT" desc:"the address of the streaming service"`
Cluster string `yaml:"events_cluster" env:"AUDIT_EVENTS_CLUSTER" desc:"the clusterID of the streaming service. Mandatory when using nats"`
ConsumerGroup string `yaml:"events_group" env:"AUDIT_EVENTS_GROUP" desc:"the customergroup of the service. One group will only get one vopy of an event"`
Endpoint string `yaml:"endpoint" env:"AUDIT_EVENTS_ENDPOINT" desc:"the address of the streaming service"`
Cluster string `yaml:"cluster" env:"AUDIT_EVENTS_CLUSTER" desc:"the clusterID of the streaming service. Mandatory when using nats"`
ConsumerGroup string `yaml:"group" env:"AUDIT_EVENTS_GROUP" desc:"the customergroup of the service. One group will only get one copy of an event"`
}
// Auditlog holds audit log information

View File

@@ -5,7 +5,7 @@ import (
"time"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/cs3org/reva/v2/pkg/storagespace"
group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
@@ -453,7 +453,7 @@ func extractFileDetails(ref *provider.Reference, owner *user.UserId) (string, st
id, path := "", ""
if ref != nil {
path = ref.GetPath()
id, _ = utils.FormatStorageSpaceReference(ref)
id, _ = storagespace.FormatReference(ref)
}
uid := ""

View File

@@ -0,0 +1,37 @@
SHELL := bash
NAME := auth-basic
include ../../.make/recursion.mk
############ tooling ############
ifneq (, $(shell which go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
include ../../.bingo/Variables.mk
endif
############ go tooling ############
include ../../.make/go.mk
############ release ############
include ../../.make/release.mk
############ docs generate ############
include ../../.make/docs.mk
.PHONY: docs-generate
docs-generate: config-docs-generate
############ generate ############
include ../../.make/generate.mk
.PHONY: ci-go-generate
ci-go-generate: # CI runs ci-node-generate automatically before this target
.PHONY: ci-node-generate
ci-node-generate:
############ licenses ############
.PHONY: ci-node-check-licenses
ci-node-check-licenses:
.PHONY: ci-node-save-licenses
ci-node-save-licenses:

View File

@@ -0,0 +1,14 @@
package main
import (
"os"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/command"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config/defaults"
)
func main() {
if err := command.Execute(defaults.DefaultConfig()); err != nil {
os.Exit(1)
}
}

View File

@@ -1,227 +0,0 @@
package command
import (
"context"
"flag"
"fmt"
"os"
"path"
"path/filepath"
"github.com/cs3org/reva/v2/cmd/revad/runtime"
"github.com/gofrs/uuid"
"github.com/oklog/run"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config/parser"
"github.com/owncloud/ocis/extensions/storage/pkg/server/debug"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/ldap"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/owncloud/ocis/ocis-pkg/tracing"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// Command is the entrypoint for the auth-basic command.
func AuthBasic(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "auth-basic",
Usage: "start authprovider for basic auth",
Before: func(ctx *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logCfg := cfg.Logging
logger := log.NewLogger(
log.Level(logCfg.Level),
log.File(logCfg.File),
log.Pretty(logCfg.Pretty),
log.Color(logCfg.Color),
)
tracing.Configure(cfg.Tracing.Enabled, cfg.Tracing.Type, logger)
gr := run.Group{}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// pre-create folders
if cfg.AuthProvider == "json" && cfg.AuthProviders.JSON.File != "" {
if err := os.MkdirAll(filepath.Dir(cfg.AuthProviders.JSON.File), os.FileMode(0700)); err != nil {
return err
}
}
uuid := uuid.Must(uuid.NewV4())
pidFile := path.Join(os.TempDir(), "revad-"+c.Command.Name+"-"+uuid.String()+".pid")
rcfg := authBasicConfigFromStruct(c, cfg)
logger.Debug().
Str("server", "authbasic").
Interface("reva-config", rcfg).
Msg("config")
if cfg.AuthProvider == "ldap" {
ldapCfg := cfg.AuthProviders.LDAP
if err := ldap.WaitForCA(logger, ldapCfg.Insecure, ldapCfg.CACert); err != nil {
logger.Error().Err(err).Msg("The configured LDAP CA cert does not exist")
return err
}
}
gr.Add(func() error {
runtime.RunWithOptions(rcfg, pidFile, runtime.WithLogger(&logger.Logger))
return nil
}, func(_ error) {
logger.Info().
Str("server", c.Command.Name).
Msg("Shutting down server")
cancel()
})
debugServer, err := debug.Server(
debug.Name(c.Command.Name+"-debug"),
debug.Addr(cfg.Debug.Addr),
debug.Logger(logger),
debug.Context(ctx),
debug.Pprof(cfg.Debug.Pprof),
debug.Zpages(cfg.Debug.Zpages),
debug.Token(cfg.Debug.Token),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
cancel()
})
if !cfg.Supervised {
sync.Trap(&gr, cancel)
}
return gr.Run()
},
}
}
// authBasicConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
func authBasicConfigFromStruct(c *cli.Context, cfg *config.Config) map[string]interface{} {
rcfg := map[string]interface{}{
"core": map[string]interface{}{
"tracing_enabled": cfg.Tracing.Enabled,
"tracing_endpoint": cfg.Tracing.Endpoint,
"tracing_collector": cfg.Tracing.Collector,
"tracing_service_name": c.Command.Name,
},
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,
"address": cfg.GRPC.Addr,
// TODO build services dynamically
"services": map[string]interface{}{
"authprovider": map[string]interface{}{
"auth_manager": cfg.AuthProvider,
"auth_managers": map[string]interface{}{
"json": map[string]interface{}{
"users": cfg.AuthProviders.JSON.File,
},
"ldap": ldapConfigFromString(cfg.AuthProviders.LDAP),
"owncloudsql": map[string]interface{}{
"dbusername": cfg.AuthProviders.OwnCloudSQL.DBUsername,
"dbpassword": cfg.AuthProviders.OwnCloudSQL.DBPassword,
"dbhost": cfg.AuthProviders.OwnCloudSQL.DBHost,
"dbport": cfg.AuthProviders.OwnCloudSQL.DBPort,
"dbname": cfg.AuthProviders.OwnCloudSQL.DBName,
"idp": cfg.AuthProviders.OwnCloudSQL.IDP,
"nobody": cfg.AuthProviders.OwnCloudSQL.Nobody,
"join_username": cfg.AuthProviders.OwnCloudSQL.JoinUsername,
"join_ownclouduuid": cfg.AuthProviders.OwnCloudSQL.JoinOwnCloudUUID,
},
},
},
},
},
}
return rcfg
}
// AuthBasicSutureService allows for the storage-authbasic command to be embedded and supervised by a suture supervisor tree.
type AuthBasicSutureService struct {
cfg *config.Config
}
// NewAuthBasicSutureService creates a new store.AuthBasicSutureService
func NewAuthBasic(cfg *ociscfg.Config) suture.Service {
cfg.AuthBasic.Commons = cfg.Commons
return AuthBasicSutureService{
cfg: cfg.AuthBasic,
}
}
func (s AuthBasicSutureService) Serve(ctx context.Context) error {
f := &flag.FlagSet{}
cmdFlags := AuthBasic(s.cfg).Flags
for k := range cmdFlags {
if err := cmdFlags[k].Apply(f); err != nil {
return err
}
}
cliCtx := cli.NewContext(nil, f, nil)
if AuthBasic(s.cfg).Before != nil {
if err := AuthBasic(s.cfg).Before(cliCtx); err != nil {
return err
}
}
if err := AuthBasic(s.cfg).Action(cliCtx); err != nil {
return err
}
return nil
}
func ldapConfigFromString(cfg config.LDAPProvider) map[string]interface{} {
return map[string]interface{}{
"uri": cfg.URI,
"cacert": cfg.CACert,
"insecure": cfg.Insecure,
"bind_username": cfg.BindDN,
"bind_password": cfg.BindPassword,
"user_base_dn": cfg.UserBaseDN,
"group_base_dn": cfg.GroupBaseDN,
"user_filter": cfg.UserFilter,
"group_filter": cfg.GroupFilter,
"user_scope": cfg.UserScope,
"group_scope": cfg.GroupScope,
"user_objectclass": cfg.UserObjectClass,
"group_objectclass": cfg.GroupObjectClass,
"login_attributes": cfg.LoginAttributes,
"idp": cfg.IDP,
"user_schema": map[string]interface{}{
"id": cfg.UserSchema.ID,
"idIsOctetString": cfg.UserSchema.IDIsOctetString,
"mail": cfg.UserSchema.Mail,
"displayName": cfg.UserSchema.DisplayName,
"userName": cfg.UserSchema.Username,
},
"group_schema": map[string]interface{}{
"id": cfg.GroupSchema.ID,
"idIsOctetString": cfg.GroupSchema.IDIsOctetString,
"mail": cfg.GroupSchema.Mail,
"displayName": cfg.GroupSchema.DisplayName,
"groupName": cfg.GroupSchema.Groupname,
"member": cfg.GroupSchema.Member,
},
}
}

View File

@@ -0,0 +1,57 @@
package command
import (
"fmt"
"net/http"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config/parser"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
"http://%s/healthz",
cfg.Debug.Addr,
),
)
if err != nil {
logger.Fatal().
Err(err).
Msg("Failed to request health check")
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")
}
logger.Debug().
Int("code", resp.StatusCode).
Msg("Health got a good state")
return nil
},
}
}

View File

@@ -0,0 +1,64 @@
package command
import (
"context"
"os"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocis-auth-basic command.
func Execute(cfg *config.Config) error {
app := clihelper.DefaultApp(&cli.App{
Name: "auth-basic",
Usage: "Provide basic authentication for oCIS",
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
return app.Run(os.Args)
}
// SutureService allows for the auth-basic command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config
}
// NewSutureService creates a new auth-basic.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
cfg.AuthBasic.Commons = cfg.Commons
return SutureService{
cfg: cfg.AuthBasic,
}
}
func (s SutureService) Serve(ctx context.Context) error {
s.cfg.Context = ctx
if err := Execute(s.cfg); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,120 @@
package command
import (
"context"
"fmt"
"os"
"path"
"github.com/cs3org/reva/v2/cmd/revad/runtime"
"github.com/gofrs/uuid"
"github.com/oklog/run"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config/parser"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/logging"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/revaconfig"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/server/debug"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/tracing"
"github.com/owncloud/ocis/ocis-pkg/ldap"
"github.com/owncloud/ocis/ocis-pkg/service/external"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entry point for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg, logger)
if err != nil {
return err
}
gr := run.Group{}
ctx, cancel := defineContext(cfg)
defer cancel()
pidFile := path.Join(os.TempDir(), "revad-"+cfg.Service.Name+"-"+uuid.Must(uuid.NewV4()).String()+".pid")
rcfg := revaconfig.AuthBasicConfigFromStruct(cfg)
// the reva runtime calls os.Exit in the case of a failure and there is no way for the oCIS
// runtime to catch it and restart a reva service. Therefore we need to ensure the service has
// everything it needs, before starting the service.
// In this case: CA certificates
if cfg.AuthProvider == "ldap" {
ldapCfg := cfg.AuthProviders.LDAP
if err := ldap.WaitForCA(logger, ldapCfg.Insecure, ldapCfg.CACert); err != nil {
logger.Error().Err(err).Msg("The configured LDAP CA cert does not exist")
return err
}
}
gr.Add(func() error {
runtime.RunWithOptions(rcfg, pidFile, runtime.WithLogger(&logger.Logger))
return nil
}, func(_ error) {
logger.Info().
Str("server", cfg.Service.Name).
Msg("Shutting down server")
cancel()
})
debugServer, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
cancel()
})
if !cfg.Supervised {
sync.Trap(&gr, cancel)
}
if err := external.RegisterGRPCEndpoint(
ctx,
cfg.GRPC.Namespace+"."+cfg.Service.Name,
uuid.Must(uuid.NewV4()).String(),
cfg.GRPC.Addr,
version.String,
logger,
); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc endpoint")
}
return gr.Run()
},
}
}
// defineContext sets the context for the extension. If there is a context configured it will create a new child from it,
// if not, it will create a root context that can be cancelled.
func defineContext(cfg *config.Config) (context.Context, context.CancelFunc) {
return func() (context.Context, context.CancelFunc) {
if cfg.Context == nil {
return context.WithCancel(context.Background())
}
return context.WithCancel(cfg.Context)
}()
}

View File

@@ -0,0 +1,50 @@
package command
import (
"fmt"
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
"github.com/urfave/cli/v2"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.GRPC.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}
table := tw.NewWriter(os.Stdout)
table.SetHeader([]string{"Version", "Address", "Id"})
table.SetAutoFormatHeaders(false)
for _, s := range services {
for _, n := range s.Nodes {
table.Append([]string{s.Version, n.Address, n.Id})
}
}
table.Render()
return nil
},
}
}

View File

@@ -1,23 +1,29 @@
package config
import "github.com/owncloud/ocis/ocis-pkg/shared"
import (
"context"
"github.com/owncloud/ocis/ocis-pkg/shared"
)
type Config struct {
*shared.Commons `yaml:"-"`
Service Service `yaml:"-"`
Tracing *Tracing `yaml:"tracing"`
Logging *Logging `yaml:"log"`
Log *Log `yaml:"log"`
Debug Debug `yaml:"debug"`
Supervised bool `yaml:"-"`
GRPC GRPCConfig `yaml:"grpc"`
TokenManager *TokenManager `yaml:"token_manager"`
Reva *Reva `yaml:"reva"`
SkipUserGroupsInToken bool `yaml:"skip_user_groups_in_token"`
SkipUserGroupsInToken bool `yaml:"skip_user_groups_in_token" env:"AUTH_BASIC_SKIP_USER_GROUPS_IN_TOKEN"`
AuthProvider string `yaml:"auth_provider" env:"AUTH_BASIC_AUTH_PROVIDER" desc:"The auth provider which should be used by the service"`
AuthProviders AuthProviders `yaml:"auth_providers"`
Supervised bool `yaml:"-"`
Context context.Context `yaml:"-"`
}
type Tracing struct {
Enabled bool `yaml:"enabled" env:"OCIS_TRACING_ENABLED;AUTH_BASIC_TRACING_ENABLED" desc:"Activates tracing."`
@@ -26,7 +32,7 @@ type Tracing struct {
Collector string `yaml:"collector" env:"OCIS_TRACING_COLLECTOR;AUTH_BASIC_TRACING_COLLECTOR"`
}
type Logging struct {
type Log struct {
Level string `yaml:"level" env:"OCIS_LOG_LEVEL;AUTH_BASIC_LOG_LEVEL" desc:"The log level."`
Pretty bool `yaml:"pretty" env:"OCIS_LOG_PRETTY;AUTH_BASIC_LOG_PRETTY" desc:"Activates pretty log output."`
Color bool `yaml:"color" env:"OCIS_LOG_COLOR;AUTH_BASIC_LOG_COLOR" desc:"Activates colorized log output."`
@@ -45,66 +51,66 @@ type Debug struct {
}
type GRPCConfig struct {
Addr string `yaml:"addr" env:"AUTH_BASIC_GRPC_ADDR" desc:"The address of the grpc service."`
Protocol string `yaml:"protocol" env:"AUTH_BASIC_GRPC_PROTOCOL" desc:"The transport protocol of the grpc service."`
Addr string `yaml:"addr" env:"AUTH_BASIC_GRPC_ADDR" desc:"The address of the grpc service."`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"AUTH_BASIC_GRPC_PROTOCOL" desc:"The transport protocol of the grpc service."`
}
type AuthProviders struct {
JSON JSONProvider `yaml:"json"`
LDAP LDAPProvider `yaml:"ldap"`
OwnCloudSQL OwnCloudSQLProvider `yaml:"owncloud_sql"`
OwnCloudSQL OwnCloudSQLProvider `yaml:"owncloudsql"`
JSON JSONProvider `yaml:"json,omitempty"` // not supported by the oCIS product, therefore not part of docs
}
type JSONProvider struct {
File string `yaml:"file" env:"AUTH_BASIC_JSON_PROVIDER_FILE" desc:"The file to which the json provider writes the data."`
File string `yaml:"file,omitempty"`
}
type LDAPProvider struct {
URI string `env:"LDAP_URI;AUTH_BASIC_LDAP_URI"`
CACert string `env:"LDAP_CACERT;AUTH_BASIC_LDAP_CACERT"`
Insecure bool `env:"LDAP_INSECURE;AUTH_BASIC_LDAP_INSECURE"`
BindDN string `env:"LDAP_BIND_DN;AUTH_BASIC_LDAP_BIND_DN"`
BindPassword string `yaml:"bind_password" env:"LDAP_BIND_PASSWORD;AUTH_BASIC_LDAP_BIND_PASSWORD"`
UserBaseDN string `env:"LDAP_USER_BASE_DN;AUTH_BASIC_LDAP_USER_BASE_DN"`
GroupBaseDN string `env:"LDAP_GROUP_BASE_DN;AUTH_BASIC_LDAP_GROUP_BASE_DN"`
UserScope string `env:"LDAP_USER_SCOPE;AUTH_BASIC_LDAP_USER_SCOPE"`
GroupScope string `env:"LDAP_GROUP_SCOPE;AUTH_BASIC_LDAP_GROUP_SCOPE"`
UserFilter string `env:"LDAP_USERFILTER;AUTH_BASIC_LDAP_USERFILTER"`
GroupFilter string `env:"LDAP_GROUPFILTER;AUTH_BASIC_LDAP_USERFILTER"`
UserObjectClass string `env:"LDAP_USER_OBJECTCLASS;AUTH_BASIC_LDAP_USER_OBJECTCLASS"`
GroupObjectClass string `env:"LDAP_GROUP_OBJECTCLASS;AUTH_BASIC_LDAP_GROUP_OBJECTCLASS"`
LoginAttributes []string `env:"LDAP_LOGIN_ATTRIBUTES;AUTH_BASIC_LDAP_LOGIN_ATTRIBUTES"`
IDP string `env:"OCIS_URL;AUTH_BASIC_IDP_URL"` // TODO what is this for?
GatewayEndpoint string // TODO do we need this here?
UserSchema LDAPUserSchema
GroupSchema LDAPGroupSchema
URI string `yaml:"uri" env:"LDAP_URI;AUTH_BASIC_LDAP_URI"`
CACert string `yaml:"ca_cert" env:"LDAP_CACERT;AUTH_BASIC_LDAP_CACERT"`
Insecure bool `yaml:"insecure" env:"LDAP_INSECURE;AUTH_BASIC_LDAP_INSECURE"`
BindDN string `yaml:"bind_dn" env:"LDAP_BIND_DN;AUTH_BASIC_LDAP_BIND_DN"`
BindPassword string `yaml:"bind_password" env:"LDAP_BIND_PASSWORD;AUTH_BASIC_LDAP_BIND_PASSWORD"`
UserBaseDN string `yaml:"user_base_dn" env:"LDAP_USER_BASE_DN;AUTH_BASIC_LDAP_USER_BASE_DN"`
GroupBaseDN string `yaml:"group_base_dn" env:"LDAP_GROUP_BASE_DN;AUTH_BASIC_LDAP_GROUP_BASE_DN"`
UserScope string `yaml:"user_scope" env:"LDAP_USER_SCOPE;AUTH_BASIC_LDAP_USER_SCOPE"`
GroupScope string `yaml:"group_scope" env:"LDAP_GROUP_SCOPE;AUTH_BASIC_LDAP_GROUP_SCOPE"`
UserFilter string `yaml:"user_filter" env:"LDAP_USERFILTER;AUTH_BASIC_LDAP_USERFILTER"`
GroupFilter string `yaml:"group_filter" env:"LDAP_GROUPFILTER;AUTH_BASIC_LDAP_USERFILTER"`
UserObjectClass string `yaml:"user_object_filter" env:"LDAP_USER_OBJECTCLASS;AUTH_BASIC_LDAP_USER_OBJECTCLASS"`
GroupObjectClass string `yaml:"group_object_class" env:"LDAP_GROUP_OBJECTCLASS;AUTH_BASIC_LDAP_GROUP_OBJECTCLASS"`
LoginAttributes []string `yaml:"login_attributes" env:"LDAP_LOGIN_ATTRIBUTES;AUTH_BASIC_LDAP_LOGIN_ATTRIBUTES"`
IDP string `yaml:"idp" env:"OCIS_URL;AUTH_BASIC_IDP_URL"`
UserSchema LDAPUserSchema `yaml:"user_schema"`
GroupSchema LDAPGroupSchema `yaml:"group_schema"`
}
type LDAPUserSchema struct {
ID string `env:"LDAP_USER_SCHEMA_ID;AUTH_BASIC_LDAP_USER_SCHEMA_ID"`
IDIsOctetString bool `env:"LDAP_USER_SCHEMA_ID_IS_OCTETSTRING;AUTH_BASIC_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING"`
Mail string `env:"LDAP_USER_SCHEMA_MAIL;AUTH_BASIC_LDAP_USER_SCHEMA_MAIL"`
DisplayName string `env:"LDAP_USER_SCHEMA_DISPLAYNAME;AUTH_BASIC_LDAP_USER_SCHEMA_DISPLAYNAME"`
Username string `env:"LDAP_USER_SCHEMA_USERNAME;AUTH_BASIC_LDAP_USER_SCHEMA_USERNAME"`
ID string `yaml:"id" env:"LDAP_USER_SCHEMA_ID;AUTH_BASIC_LDAP_USER_SCHEMA_ID"`
IDIsOctetString bool `yaml:"id_is_octet_string" env:"LDAP_USER_SCHEMA_ID_IS_OCTETSTRING;AUTH_BASIC_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING"`
Mail string `yaml:"mail" env:"LDAP_USER_SCHEMA_MAIL;AUTH_BASIC_LDAP_USER_SCHEMA_MAIL"`
DisplayName string `yaml:"display_name" env:"LDAP_USER_SCHEMA_DISPLAYNAME;AUTH_BASIC_LDAP_USER_SCHEMA_DISPLAYNAME"`
Username string `yaml:"user_name" env:"LDAP_USER_SCHEMA_USERNAME;AUTH_BASIC_LDAP_USER_SCHEMA_USERNAME"`
}
type LDAPGroupSchema struct {
ID string `env:"LDAP_GROUP_SCHEMA_ID;AUTH_BASIC_LDAP_GROUP_SCHEMA_ID"`
IDIsOctetString bool `env:"LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING;AUTH_BASIC_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING"`
Mail string `env:"LDAP_GROUP_SCHEMA_MAIL;AUTH_BASIC_LDAP_GROUP_SCHEMA_MAIL"`
DisplayName string `env:"LDAP_GROUP_SCHEMA_DISPLAYNAME;AUTH_BASIC_LDAP_GROUP_SCHEMA_DISPLAYNAME"`
Groupname string `env:"LDAP_GROUP_SCHEMA_GROUPNAME;AUTH_BASIC_LDAP_GROUP_SCHEMA_GROUPNAME"`
Member string `env:"LDAP_GROUP_SCHEMA_MEMBER;AUTH_BASIC_LDAP_GROUP_SCHEMA_MEMBER"`
ID string `yaml:"id" env:"LDAP_GROUP_SCHEMA_ID;AUTH_BASIC_LDAP_GROUP_SCHEMA_ID"`
IDIsOctetString bool `yaml:"id_is_octet_string" env:"LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING;AUTH_BASIC_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING"`
Mail string `yaml:"mail" env:"LDAP_GROUP_SCHEMA_MAIL;AUTH_BASIC_LDAP_GROUP_SCHEMA_MAIL"`
DisplayName string `yaml:"display_name" env:"LDAP_GROUP_SCHEMA_DISPLAYNAME;AUTH_BASIC_LDAP_GROUP_SCHEMA_DISPLAYNAME"`
Groupname string `yaml:"group_name" env:"LDAP_GROUP_SCHEMA_GROUPNAME;AUTH_BASIC_LDAP_GROUP_SCHEMA_GROUPNAME"`
Member string `yaml:"member" env:"LDAP_GROUP_SCHEMA_MEMBER;AUTH_BASIC_LDAP_GROUP_SCHEMA_MEMBER"`
}
type OwnCloudSQLProvider struct {
DBUsername string
DBPassword string
DBHost string
DBPort int
DBName string
IDP string // TODO do we need this?
Nobody int64 // TODO what is this?
JoinUsername bool
JoinOwnCloudUUID bool
DBUsername string `yaml:"db_username" env:"AUTH_BASIC_OWNCLOUDSQL_DB_USERNAME"`
DBPassword string `yaml:"db_password" env:"AUTH_BASIC_OWNCLOUDSQL_DB_PASSWORD"`
DBHost string `yaml:"db_host" env:"AUTH_BASIC_OWNCLOUDSQL_DB_HOST"`
DBPort int `yaml:"db_port" env:"AUTH_BASIC_OWNCLOUDSQL_DB_PORT"`
DBName string `yaml:"db_name" env:"AUTH_BASIC_OWNCLOUDSQL_DB_NAME"`
IDP string `yaml:"idp" env:"AUTH_BASIC_OWNCLOUDSQL_IDP"`
Nobody int64 `yaml:"nobody" env:"AUTH_BASIC_OWNCLOUDSQL_NOBODY"` // TODO what is this?
JoinUsername bool `yaml:"join_username" env:"AUTH_BASIC_OWNCLOUDSQL_JOIN_USERNAME"`
JoinOwnCloudUUID bool `yaml:"join_owncloud_uuid" env:"AUTH_BASIC_OWNCLOUDSQL_JOIN_OWNCLOUD_UUID"`
}

View File

@@ -23,8 +23,9 @@ func DefaultConfig() *config.Config {
Zpages: false,
},
GRPC: config.GRPCConfig{
Addr: "127.0.0.1:9146",
Protocol: "tcp",
Addr: "127.0.0.1:9146",
Namespace: "com.owncloud.api",
Protocol: "tcp",
},
Service: config.Service{
Name: "auth-basic",
@@ -80,15 +81,15 @@ func DefaultConfig() *config.Config {
func EnsureDefaults(cfg *config.Config) {
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Logging == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Logging = &config.Logging{
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &config.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Logging == nil {
cfg.Logging = &config.Logging{}
} else if cfg.Log == nil {
cfg.Log = &config.Log{}
}
// provide with defaults for shared tracing, since we need a valid destination address for BindEnv.
if cfg.Tracing == nil && cfg.Commons != nil && cfg.Commons.Tracing != nil {

View File

@@ -0,0 +1,17 @@
package logging
import (
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// LoggerFromConfig initializes a service-specific logger instance.
func Configure(name string, cfg *config.Log) log.Logger {
return log.NewLogger(
log.Name(name),
log.Level(cfg.Level),
log.Pretty(cfg.Pretty),
log.Color(cfg.Color),
log.File(cfg.File),
)
}

View File

@@ -0,0 +1,83 @@
package revaconfig
import "github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
// AuthBasicConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
func AuthBasicConfigFromStruct(cfg *config.Config) map[string]interface{} {
rcfg := map[string]interface{}{
"core": map[string]interface{}{
"tracing_enabled": cfg.Tracing.Enabled,
"tracing_endpoint": cfg.Tracing.Endpoint,
"tracing_collector": cfg.Tracing.Collector,
"tracing_service_name": cfg.Service.Name,
},
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,
"address": cfg.GRPC.Addr,
// TODO build services dynamically
"services": map[string]interface{}{
"authprovider": map[string]interface{}{
"auth_manager": cfg.AuthProvider,
"auth_managers": map[string]interface{}{
"json": map[string]interface{}{
"users": cfg.AuthProviders.JSON.File,
},
"ldap": ldapConfigFromString(cfg.AuthProviders.LDAP),
"owncloudsql": map[string]interface{}{
"dbusername": cfg.AuthProviders.OwnCloudSQL.DBUsername,
"dbpassword": cfg.AuthProviders.OwnCloudSQL.DBPassword,
"dbhost": cfg.AuthProviders.OwnCloudSQL.DBHost,
"dbport": cfg.AuthProviders.OwnCloudSQL.DBPort,
"dbname": cfg.AuthProviders.OwnCloudSQL.DBName,
"idp": cfg.AuthProviders.OwnCloudSQL.IDP,
"nobody": cfg.AuthProviders.OwnCloudSQL.Nobody,
"join_username": cfg.AuthProviders.OwnCloudSQL.JoinUsername,
"join_ownclouduuid": cfg.AuthProviders.OwnCloudSQL.JoinOwnCloudUUID,
},
},
},
},
},
}
return rcfg
}
func ldapConfigFromString(cfg config.LDAPProvider) map[string]interface{} {
return map[string]interface{}{
"uri": cfg.URI,
"cacert": cfg.CACert,
"insecure": cfg.Insecure,
"bind_username": cfg.BindDN,
"bind_password": cfg.BindPassword,
"user_base_dn": cfg.UserBaseDN,
"group_base_dn": cfg.GroupBaseDN,
"user_filter": cfg.UserFilter,
"group_filter": cfg.GroupFilter,
"user_scope": cfg.UserScope,
"group_scope": cfg.GroupScope,
"user_objectclass": cfg.UserObjectClass,
"group_objectclass": cfg.GroupObjectClass,
"login_attributes": cfg.LoginAttributes,
"idp": cfg.IDP,
"user_schema": map[string]interface{}{
"id": cfg.UserSchema.ID,
"idIsOctetString": cfg.UserSchema.IDIsOctetString,
"mail": cfg.UserSchema.Mail,
"displayName": cfg.UserSchema.DisplayName,
"userName": cfg.UserSchema.Username,
},
"group_schema": map[string]interface{}{
"id": cfg.GroupSchema.ID,
"idIsOctetString": cfg.GroupSchema.IDIsOctetString,
"mail": cfg.GroupSchema.Mail,
"displayName": cfg.GroupSchema.DisplayName,
"groupName": cfg.GroupSchema.Groupname,
"member": cfg.GroupSchema.Member,
},
}
}

View File

@@ -0,0 +1,50 @@
package debug
import (
"context"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Context context.Context
Config *config.Config
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Context provides a function to set the context option.
func Context(val context.Context) Option {
return func(o *Options) {
o.Context = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}

View File

@@ -0,0 +1,63 @@
package debug
import (
"io"
"net/http"
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/service/debug"
"github.com/owncloud/ocis/ocis-pkg/version"
)
// Server initializes the debug service and server.
func Server(opts ...Option) (*http.Server, error) {
options := newOptions(opts...)
return debug.NewService(
debug.Logger(options.Logger),
debug.Name(options.Config.Service.Name),
debug.Version(version.String),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),
debug.Pprof(options.Config.Debug.Pprof),
debug.Zpages(options.Config.Debug.Zpages),
debug.Health(health(options.Config)),
debug.Ready(ready(options.Config)),
//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
), nil
}
// health implements the health check.
func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}
// ready implements the ready check.
func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}

View File

@@ -0,0 +1,18 @@
package tracing
import (
"github.com/owncloud/ocis/extensions/auth-basic/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/tracing"
"go.opentelemetry.io/otel/trace"
)
var (
// TraceProvider is the global trace provider for the service.
TraceProvider = trace.NewNoopTracerProvider()
)
func Configure(cfg *config.Config, logger log.Logger) error {
tracing.Configure(cfg.Tracing.Enabled, cfg.Tracing.Type, logger)
return nil
}

View File

@@ -0,0 +1,37 @@
SHELL := bash
NAME := auth-bearer
include ../../.make/recursion.mk
############ tooling ############
ifneq (, $(shell which go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
include ../../.bingo/Variables.mk
endif
############ go tooling ############
include ../../.make/go.mk
############ release ############
include ../../.make/release.mk
############ docs generate ############
include ../../.make/docs.mk
.PHONY: docs-generate
docs-generate: config-docs-generate
############ generate ############
include ../../.make/generate.mk
.PHONY: ci-go-generate
ci-go-generate: # CI runs ci-node-generate automatically before this target
.PHONY: ci-node-generate
ci-node-generate:
############ licenses ############
.PHONY: ci-node-check-licenses
ci-node-check-licenses:
.PHONY: ci-node-save-licenses
ci-node-save-licenses:

View File

@@ -0,0 +1,14 @@
package main
import (
"os"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/command"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/config/defaults"
)
func main() {
if err := command.Execute(defaults.DefaultConfig()); err != nil {
os.Exit(1)
}
}

View File

@@ -1,165 +0,0 @@
package command
import (
"context"
"flag"
"fmt"
"os"
"path"
"github.com/cs3org/reva/v2/cmd/revad/runtime"
"github.com/gofrs/uuid"
"github.com/oklog/run"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/config"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/config/parser"
"github.com/owncloud/ocis/extensions/storage/pkg/server/debug"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/owncloud/ocis/ocis-pkg/tracing"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// AuthBearer is the entrypoint for the auth-bearer command.
func AuthBearer(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "auth-bearer",
Usage: "start authprovider for bearer auth",
Before: func(ctx *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logCfg := cfg.Logging
logger := log.NewLogger(
log.Level(logCfg.Level),
log.File(logCfg.File),
log.Pretty(logCfg.Pretty),
log.Color(logCfg.Color),
)
tracing.Configure(cfg.Tracing.Enabled, cfg.Tracing.Type, logger)
gr := run.Group{}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
uuid := uuid.Must(uuid.NewV4())
pidFile := path.Join(os.TempDir(), "revad-"+c.Command.Name+"-"+uuid.String()+".pid")
rcfg := authBearerConfigFromStruct(c, cfg)
gr.Add(func() error {
runtime.RunWithOptions(
rcfg,
pidFile,
runtime.WithLogger(&logger.Logger),
)
return nil
}, func(_ error) {
logger.Info().
Str("server", c.Command.Name).
Msg("Shutting down server")
cancel()
})
debugServer, err := debug.Server(
debug.Name(c.Command.Name+"-debug"),
debug.Addr(cfg.Debug.Addr),
debug.Logger(logger),
debug.Context(ctx),
debug.Pprof(cfg.Debug.Pprof),
debug.Zpages(cfg.Debug.Zpages),
debug.Token(cfg.Debug.Token),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("failed to initialize server")
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
cancel()
})
if !cfg.Supervised {
sync.Trap(&gr, cancel)
}
return gr.Run()
},
}
}
// authBearerConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
func authBearerConfigFromStruct(c *cli.Context, cfg *config.Config) map[string]interface{} {
return map[string]interface{}{
"core": map[string]interface{}{
"tracing_enabled": cfg.Tracing.Enabled,
"tracing_endpoint": cfg.Tracing.Endpoint,
"tracing_collector": cfg.Tracing.Collector,
"tracing_service_name": c.Command.Name,
},
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,
"address": cfg.GRPC.Addr,
// TODO build services dynamically
"services": map[string]interface{}{
"authprovider": map[string]interface{}{
"auth_manager": cfg.AuthProvider,
"auth_managers": map[string]interface{}{
"oidc": map[string]interface{}{
"issuer": cfg.AuthProviders.OIDC.Issuer,
"insecure": cfg.AuthProviders.OIDC.Insecure,
"id_claim": cfg.AuthProviders.OIDC.IDClaim,
"uid_claim": cfg.AuthProviders.OIDC.UIDClaim,
"gid_claim": cfg.AuthProviders.OIDC.GIDClaim,
},
},
},
},
},
}
}
// AuthBearerSutureService allows for the storage-gateway command to be embedded and supervised by a suture supervisor tree.
type AuthBearerSutureService struct {
cfg *config.Config
}
// NewAuthBearerSutureService creates a new gateway.AuthBearerSutureService
func NewAuthBearer(cfg *ociscfg.Config) suture.Service {
cfg.AuthBearer.Commons = cfg.Commons
return AuthBearerSutureService{
cfg: cfg.AuthBearer,
}
}
func (s AuthBearerSutureService) Serve(ctx context.Context) error {
cmd := AuthBearer(s.cfg)
f := &flag.FlagSet{}
cmdFlags := cmd.Flags
for k := range cmdFlags {
if err := cmdFlags[k].Apply(f); err != nil {
return err
}
}
cliCtx := cli.NewContext(nil, f, nil)
if cmd.Before != nil {
if err := cmd.Before(cliCtx); err != nil {
return err
}
}
if err := cmd.Action(cliCtx); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,57 @@
package command
import (
"fmt"
"net/http"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/config"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/config/parser"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
"http://%s/healthz",
cfg.Debug.Addr,
),
)
if err != nil {
logger.Fatal().
Err(err).
Msg("Failed to request health check")
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")
}
logger.Debug().
Int("code", resp.StatusCode).
Msg("Health got a good state")
return nil
},
}
}

View File

@@ -0,0 +1,64 @@
package command
import (
"context"
"os"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocis-auth-bearer command.
func Execute(cfg *config.Config) error {
app := clihelper.DefaultApp(&cli.App{
Name: "auth-bearer",
Usage: "Provide bearer authentication for oCIS",
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
return app.Run(os.Args)
}
// SutureService allows for the accounts command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config
}
// NewSutureService creates a new auth-bearer.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
cfg.AuthBearer.Commons = cfg.Commons
return SutureService{
cfg: cfg.AuthBearer,
}
}
func (s SutureService) Serve(ctx context.Context) error {
s.cfg.Context = ctx
if err := Execute(s.cfg); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,107 @@
package command
import (
"context"
"fmt"
"os"
"path"
"github.com/cs3org/reva/v2/cmd/revad/runtime"
"github.com/gofrs/uuid"
"github.com/oklog/run"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/config"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/config/parser"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/logging"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/revaconfig"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/server/debug"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/tracing"
"github.com/owncloud/ocis/ocis-pkg/service/external"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entry point for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
err := parser.ParseConfig(cfg)
if err != nil {
fmt.Printf("%v", err)
}
return err
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg, logger)
if err != nil {
return err
}
gr := run.Group{}
ctx, cancel := defineContext(cfg)
defer cancel()
pidFile := path.Join(os.TempDir(), "revad-"+cfg.Service.Name+"-"+uuid.Must(uuid.NewV4()).String()+".pid")
rcfg := revaconfig.AuthBearerConfigFromStruct(cfg)
gr.Add(func() error {
runtime.RunWithOptions(rcfg, pidFile, runtime.WithLogger(&logger.Logger))
return nil
}, func(_ error) {
logger.Info().
Str("server", cfg.Service.Name).
Msg("Shutting down server")
cancel()
})
debugServer, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
cancel()
})
if !cfg.Supervised {
sync.Trap(&gr, cancel)
}
if err := external.RegisterGRPCEndpoint(
ctx,
cfg.GRPC.Namespace+"."+cfg.Service.Name,
uuid.Must(uuid.NewV4()).String(),
cfg.GRPC.Addr,
version.String,
logger,
); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc endpoint")
}
return gr.Run()
},
}
}
// defineContext sets the context for the extension. If there is a context configured it will create a new child from it,
// if not, it will create a root context that can be cancelled.
func defineContext(cfg *config.Config) (context.Context, context.CancelFunc) {
return func() (context.Context, context.CancelFunc) {
if cfg.Context == nil {
return context.WithCancel(context.Background())
}
return context.WithCancel(cfg.Context)
}()
}

View File

@@ -0,0 +1,50 @@
package command
import (
"fmt"
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/extensions/auth-bearer/pkg/config"
"github.com/urfave/cli/v2"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.GRPC.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}
table := tw.NewWriter(os.Stdout)
table.SetHeader([]string{"Version", "Address", "Id"})
table.SetAutoFormatHeaders(false)
for _, s := range services {
for _, n := range s.Nodes {
table.Append([]string{s.Version, n.Address, n.Id})
}
}
table.Render()
return nil
},
}
}

Some files were not shown because too many files have changed in this diff Show More