-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial commit for multi-tenant-configuration #37
base: master
Are you sure you want to change the base?
Changes from 49 commits
b1ccec1
a597f70
0c803f6
f40ad0d
74bc708
cd8fc84
9717219
4617bc6
597260b
f26f524
2a23c78
417986f
947ee77
9c18544
1081112
97d9224
cd776b0
f94d37b
7c57358
3966713
c7abf80
078bea0
af8ecbe
9f2e64c
ef2e9ec
f66ba67
19bddc6
3a8f52e
d2bab49
ba009f5
69db473
cd17f0e
482917e
78dcbbe
193f1c6
c252098
2060de9
da377eb
7fbe1ee
5670ab6
5429368
2712647
265c01a
0987a53
fd83e52
4512e5a
9e1e6ce
b49fbbb
1c337e2
85766ec
9a8981f
a851a27
e971f73
f610d00
3659eb8
96e7636
2446129
c32d026
646f6e7
a3cf83d
7f7f517
82f3308
b044742
c1bdb2c
f4ca5ff
0e11c1a
cde69f7
0b00ec9
c360adf
f484f77
c314f95
009f96b
0753bdc
ca6e2fd
1bd47ef
140b244
39b2a19
4cab954
ddc70ca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,14 +4,14 @@ | |
import os | ||
|
||
import requests | ||
from requests.auth import HTTPDigestAuth | ||
from requests.auth import HTTPDigestAuth, HTTPBasicAuth | ||
from requests_toolbelt import MultipartEncoder | ||
|
||
from rest_requests.request_error import RequestError | ||
|
||
|
||
def get_request(url, digest_login, element_description, asset_type_description=None, asset_description=None, | ||
stream=False): | ||
def get_request(url, login, element_description, asset_type_description=None, asset_description=None, | ||
stream=False, headers=None, use_digest=True): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
""" | ||
Make a get request to the given url with the given digest login. If the request fails with an error or a status | ||
code != 200, a Request Error with the error message /status code and the given descriptions is thrown. | ||
|
@@ -28,13 +28,21 @@ def get_request(url, digest_login, element_description, asset_type_description=N | |
:type asset_description: str | ||
:param stream: Whether to stream response | ||
:type stream: bool | ||
:param headers: The headers to include in the request | ||
:type headers: dict | ||
:return: response | ||
:raise RequestError: | ||
""" | ||
|
||
headers = headers if headers else {} | ||
if use_digest: | ||
auth = HTTPDigestAuth(login.user, login.password) | ||
headers["X-Requested-Auth"] = "Digest" | ||
else: | ||
auth = HTTPBasicAuth(login['user'], login['password']) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The structure of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
|
||
try: | ||
response = requests.get(url, auth=HTTPDigestAuth(digest_login.user, digest_login.password), | ||
headers={"X-Requested-Auth": "Digest"}, stream=stream) | ||
response = requests.get(url, auth=auth, headers=headers, stream=stream) | ||
except Exception as e: | ||
raise RequestError.with_error(url, str(e), element_description, asset_type_description, asset_description) | ||
|
||
|
@@ -129,3 +137,41 @@ def big_post_request(url, digest_login, element_description, asset_type_descript | |
raise RequestError.with_status_code(url, str(response.status_code), element_description, asset_type_description, | ||
asset_description) | ||
return response | ||
|
||
|
||
def put_request(url, digest_login, element_description, asset_type_description=None, asset_description=None, | ||
data=None, files=None): | ||
""" | ||
Make a put request to the given url with the given digest login. If the request fails with an error or a status | ||
code != 200, a Request Error with the error message /status code and the given descriptions is thrown. | ||
|
||
:param url: URL to make put request to | ||
:type url: str | ||
:param digest_login: The login credentials for digest authentication | ||
:type digest_login: DigestLogin | ||
:param element_description: Element description in case of errors, e.g. 'event', 'series', 'tenants' | ||
:type element_description: str | ||
:param asset_type_description: Asset type type description in case of errors, e.g. 'series', 'episode' | ||
:type asset_type_description: str | ||
:param asset_description: Asset description in case of errors, e.g. 'Dublin Core catalogs', 'ACL' | ||
:type asset_description: str | ||
:param data: Any data to attach to the request | ||
:type data: dict | ||
:param files: Any files to attach to the request | ||
:type files: dict | ||
:return: response | ||
:raise RequestError: | ||
""" | ||
|
||
auth = HTTPDigestAuth(digest_login.user, digest_login.password) | ||
headers = {"X-Requested-Auth": "Digest"} | ||
|
||
try: | ||
response = requests.put(url, auth=auth, headers=headers, data=data, files=files) | ||
except Exception as e: | ||
raise RequestError.with_error(url, str(e), element_description, asset_type_description, asset_description) | ||
|
||
if response.status_code < 200 or response.status_code > 299: | ||
raise RequestError.with_status_code(url, str(response.status_code), element_description, asset_type_description, | ||
asset_description) | ||
return response |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Multi-tenants User configuration scripts for Opencast | ||
**ToDo** | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still some work left to do here, I see. :D There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I hope I improved that a bit :D |
||
|
||
This script ... | ||
|
||
Currently this script does not ... | ||
|
||
## How to Use | ||
|
||
### Configuration | ||
|
||
The script is configured by editing the values in `config.py`: | ||
|
||
| Configuration Key | Description | Default/Example | | ||
| :---------------- | :---------------------------------------- | :--------------------------- | | ||
| `url` | The URL of the global admin node ? | https://tenant1.opencast.com | | ||
| `tenant_url_pattern` | The URL pattern of the target tenants | https://tenant2.opencast.com | | ||
| `tenant_urls` | A dictioanry of server URLs of the target tenants | https://tenant2.opencast.com | | ||
| `digest_user` | The user name of the digest user | `opencast_system_account` | | ||
| `digest_pw` | The password of the digest user | `CHANGE_ME` | | ||
| `env_path` | The id of the workflow to start on ingest | reimport-workflow | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This table is not consistent yet, but I guess you're aware. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated table. |
||
|
||
**TODo**: check the below ... | ||
|
||
_The configured digest user needs to exist on both tenants and have the same password for both of them. This is because | ||
the script ingests the assets via URL, which is faster, but the user needs to be able to access the source tenant from | ||
the target tenant for this to work. Additionally the user currently needs to have ROLE_ADMIN to be able to use | ||
`/assets/{episodeid}`._ | ||
|
||
_For the future, Basic Authentication and the use of an endpoint that doesn't require the Admin role (e.g. | ||
`api/events/{id}`) would be preferable, so you can simply add a frontend user with the necessary rights (ingest, | ||
access to the events/series) and the same password to both tenants._ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Copied over from another README, I assume - not really relevant here :D There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed that part :) |
||
|
||
#### group config: | ||
The names in the group config file must be unique per Tenant! | ||
|
||
### Usage | ||
|
||
The script can be called with the following command (all parameters in brackets are optional): | ||
|
||
`python main.py -e ENVIRONMENT [-t TENANT_ID] [-c CHECK] [-v True]` | ||
|
||
| Param | Description | | ||
| :---: | :---------- | | ||
| `-e` / `--environment` | The environment where to find the configuration file (either `staging` or `production`) | | ||
| `-t` / `--tenantid` | The id of the target tenant to be configured | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change long argument to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
| `-c` / `--check` | checks to be performed (`users`, `groups`, `cast` or `capture`) (default: `all`) | | ||
| `-v` / `--verbose` | enables logging to be prompted if set to `True` | | ||
|
||
#### example: | ||
|
||
`python main.py -e staging -t tenant1 -c groups -v True` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
## Requirements | ||
|
||
This script was written for Python 3.8. You can install the necessary packages with | ||
|
||
**ToDo check the requirements file** | ||
|
||
`pip install -r requirements.txt` | ||
|
||
Additionally, this script uses modules contained in the _lib_ directory. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Configuration | ||
|
||
# Set this to your global admin node | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There can only be one admin node right now, so "global" is kinda unnecessary. But it is important that it's not a tenant-specific URL. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed "global" . |
||
base_url = "http://localhost:8080" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know I used this in the past, but now I'd prefer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed that variable. |
||
|
||
# If you have multiple tenants, use an URL pattern. | ||
# example: | ||
# tenant_url_pattern = "https://{}.example.org" | ||
tenant_url_pattern = "http://{}:8080" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe explain that the pattern will be filled with the tenant id. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
|
||
# You can also define a dictionary of tenant URLs, which will be prioritized over the URL pattern: | ||
# # examples: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe explain why you'd want to do this: If the tenant id is not an exact part of the URL or the URLs don't follow a common pattern. Can also go into the README. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty much copied your point and added to README. |
||
# tenant_urls = { | ||
# 'tenant1': 'http://tenant1:8080', | ||
# 'tenant2': 'http://tenant2:8080' | ||
# } | ||
# tenant_urls = {'tenant1': 'https://develop.opencast.org'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One example is enough, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed the second example. |
||
|
||
# Digest User login | ||
digest_user = "opencast_system_account" | ||
digest_pw = "CHANGE_ME" | ||
|
||
# path to environment configuration file | ||
env_path = "environment/{}/opencast-organizations.yml" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe explain that the placeholder will be filled with the environment variable that's passed as an argument. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
# path to group configuration file | ||
group_path = "configurations/group_configuration.yaml" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. renamed to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe make it possible to use environment variable here, too? People might want to have separate group configs. So basically, replace if there's a placeholder here, otherwise just don't. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So far, the script did not allow for this kind of flexibility. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
{ | ||
KatrinIhler marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"groups" : [ | ||
{ | ||
"name": "System Administrators", | ||
"description": "System Administrators", | ||
"tenants": "all", | ||
"type": "closed", | ||
"members": [ | ||
{ | ||
"name": "Guy 1", | ||
"email": "[email protected]", | ||
"reason": "Operations partner", | ||
"uid": "guy-1", | ||
"tenants": "all" | ||
}, | ||
{ | ||
"name": "Guy 2", | ||
"email": "[email protected]", | ||
"reason": "Operations partner", | ||
"uid": "guy-2", | ||
"tenants": "tenant1" | ||
} | ||
], | ||
"inactive_members": [ ], | ||
"permissions": [ | ||
{ | ||
"tenants": "all", | ||
"roles": ["ROLE_ADMIN", "ROLE_SUDO"] | ||
} | ||
] | ||
}, | ||
{ | ||
"name": "Organization Administrators", | ||
"description": "Organization administrators have full access to all content of ${name}", | ||
"tenants": "all", | ||
"type": "open", | ||
"members": [], | ||
"inactive_members": [], | ||
"permissions": [ | ||
{ | ||
"tenants": "all", | ||
"roles": [ | ||
"ROLE_ADMIN_UI", | ||
"ROLE_ORG_ADMIN" | ||
] | ||
}, | ||
{ | ||
"tenants" : "tenant2", | ||
"roles": { | ||
"add": [ | ||
"ROLE_UI_EVENTS_DETAILS_ACL_VIEW", | ||
"ROLE_UI_EVENTS_DETAILS_ACL_EDIT" | ||
], | ||
"remove": [] | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
"name": "Producers", | ||
"description": "Producers have limited access to content and functionality", | ||
"tenants": "all", | ||
"type": "open", | ||
"members": [], | ||
"inactive_members": [], | ||
"permissions": [ | ||
{ | ||
"tenants": "all", | ||
"roles": [ | ||
"ROLE_ADMIN_UI", | ||
"ROLE_UI_EVENTS_CREATE" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indentation is off here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haven't looked at the json file in a while :D |
||
] | ||
}, | ||
{ | ||
"tenants" : "tenant1", | ||
"roles": { | ||
"add": [ | ||
"ROLE_UI_EVENTS_COUNTERS_VIEW" | ||
], | ||
"remove": [ | ||
"ROLE_UI_EVENTS_CREATE" | ||
] | ||
} | ||
}, | ||
{ | ||
"tenants" : "tenant2", | ||
"roles": { | ||
"add": [ | ||
"ROLE_ORG_ADMIN" | ||
], | ||
"remove": [] | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
"name": "Tenant2 Producers", | ||
"description": "Tenant2 Producers have limited access to content and functionality", | ||
"tenants": "tenant2", | ||
"type": "open", | ||
"members": [], | ||
"inactive_members": [], | ||
"permissions": [ | ||
{ | ||
"tenants": "all", | ||
"roles": [ | ||
"ROLE_ADMIN_UI" | ||
] | ||
} | ||
] | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
--- | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NICE! |
||
|
||
groups: | ||
- name: System Administrators | ||
description: System Administrators | ||
tenants: all | ||
type: closed | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed, the group types can go away. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed the group types from the yaml file. |
||
members: | ||
- name: Guy 1 | ||
email: [email protected] | ||
reason: Operations partner | ||
uid: guy1 | ||
tenants: all | ||
- name: Guy 2 | ||
email: [email protected] | ||
reason: Operations partner | ||
uid: guy2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right: I changed that in the yaml file and in the script. |
||
tenants: tenant1 | ||
inactive_members: [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens with those anyway? Oo There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume they are being ignored Oo To be honest, I did not know what to specifically do with these members. |
||
permissions: | ||
- tenants: all | ||
roles: | ||
- ROLE_ADMIN | ||
- ROLE_SUDO | ||
- name: Organization Administrators | ||
description: Organization administrators have full access to all content of {tenant_id} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe document which placeholders can be used here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added to README. |
||
tenants: all | ||
type: open | ||
members: [] | ||
inactive_members: [] | ||
permissions: | ||
- tenants: all | ||
roles: | ||
- ROLE_ADMIN_UI | ||
- ROLE_ORG_ADMIN | ||
- tenants: tenant2 | ||
roles: | ||
add: | ||
- ROLE_UI_EVENTS_DETAILS_ACL_VIEW | ||
- ROLE_UI_EVENTS_DETAILS_ACL_EDIT | ||
remove: [] | ||
- name: Producers | ||
description: Producers have limited access to content and functionality | ||
tenants: all | ||
type: open | ||
members: [] | ||
inactive_members: [] | ||
permissions: | ||
- tenants: all | ||
roles: | ||
- ROLE_ADMIN_UI | ||
- ROLE_UI_EVENTS_CREATE | ||
- tenants: tenant1 | ||
roles: | ||
add: | ||
- ROLE_UI_EVENTS_COUNTERS_VIEW | ||
remove: | ||
- ROLE_UI_EVENTS_CREATE | ||
- tenants: tenant2 | ||
roles: | ||
add: | ||
- ROLE_ORG_ADMIN | ||
remove: [] | ||
- name: Tenant1 Producers | ||
description: Tenant1 Producers have limited access to content and functionality | ||
tenants: tenant1 | ||
type: open | ||
members: | ||
- name: Guy X | ||
email: [email protected] | ||
reason: Operations partner | ||
uid: guyx | ||
tenants: all | ||
- name: Guy 2 | ||
email: [email protected] | ||
reason: Operations partner | ||
uid: guy2 | ||
tenants: tenant1 | ||
inactive_members: [] | ||
permissions: | ||
- tenants: all | ||
roles: | ||
- ROLE_ADMIN_UI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pls also rename in doc string! Change type to something like
Login
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.