GitHub user johannes-ws created a discussion: Failed when try to update rules
via endpoint /api/v1/rowlevelsecurity/{pk} with status code 201 in Superset
5.0.0
When i run this code,
import requests
import os
import json
# --- REQUIRED CONFIGURATION ---
SUPERSET_URL = os.getenv("SUPERSET_URL", "http://localhost:8088")
ADMIN_USERNAME = os.getenv("SUPERSET_USER", "admin")
ADMIN_PASSWORD = os.getenv("SUPERSET_PASSWORD", "admin")
# --- PROGRAM STUDY CODE MAPPING (KAPRODI) ---
# REQUIRED: Complete this dictionary with your data.
# Format: "short_program_name_from_role": numeric_program_code
KAPRODI_CODE_MAPPING = {
"if": 135,
"mesin": 131,
# "elektro": 133,
# Add all your kaprodi (program study) mappings here
}
def main():
"""Main function to run the automation process with CREATE or UPDATE
logic."""
# Use a session object to maintain login cookies, which are needed for
CSRF
with requests.Session() as session:
# 1. Authenticate and get CSRF token
print("1. Authenticating to Superset...")
try:
# Login
login_data = {"username": ADMIN_USERNAME, "password":
ADMIN_PASSWORD, "provider": "db"}
r_login = session.post(f"{SUPERSET_URL}/api/v1/security/login",
json=login_data)
r_login.raise_for_status()
access_token = r_login.json()["access_token"]
# Set headers for the entire session
session.headers.update({
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
})
print(" -> Authentication successful.")
# Get CSRF token
print(" -> Fetching CSRF token...")
r_csrf =
session.get(f"{SUPERSET_URL}/api/v1/security/csrf_token/")
r_csrf.raise_for_status()
csrf_token = r_csrf.json()['result']
# Add CSRF token to headers for all future state-changing
requests (POST, PUT, DELETE)
session.headers['X-CSRFToken'] = csrf_token
print(" -> CSRF token obtained.")
except requests.exceptions.RequestException as e:
print(f" -> FAILED during login/CSRF process: {e}")
return
# 2. Fetch all necessary data
print("\n2. Fetching data from Superset...")
params = {"q": json.dumps({"page_size": -1})}
try:
r_datasets = session.get(f"{SUPERSET_URL}/api/v1/dataset/",
params=params)
r_datasets.raise_for_status()
all_dataset_ids = [ds['id'] for ds in
r_datasets.json()['result']]
r_roles = session.get(f"{SUPERSET_URL}/api/v1/security/roles/",
params=params)
r_roles.raise_for_status()
roles_map = {role['name']: role['id'] for role in
r_roles.json()['result']}
# IMPORTANT CHANGE: Store the NAME and ID of existing rules in
a dictionary/map
r_rls = session.get(f"{SUPERSET_URL}/api/v1/rowlevelsecurity/",
params=params)
r_rls.raise_for_status()
existing_rules_map = {rule['name']: rule['id'] for rule in
r_rls.json()['result']}
print(f" -> Found {len(all_dataset_ids)} datasets,
{len(roles_map)} roles, and {len(existing_rules_map)} existing RLS rules.")
except requests.exceptions.RequestException as e:
print(f" -> FAILED to fetch data: {e}")
return
if not all_dataset_ids:
print("\nWARNING: No datasets found. No rules will be created
or updated.")
return
print("\n3. Processing roles and creating or updating RLS rules...")
for role_name, role_id in roles_map.items():
rule_name = None
clause = None
# Logic to determine rule_name and clause remains the same
if role_name.lower().startswith('dekan ') and role_name.lower()
!= 'dekan':
fakultas_code = role_name.split(' ', 1)[1].upper()
rule_name = f"Rule Dekan {fakultas_code}"
clause = f"kd_fak = '{fakultas_code}'"
elif role_name.lower().startswith('kaprodi ') and
role_name.lower() != 'kaprodi':
prodi_short_name = role_name.split(' ', 1)[1].lower()
prodi_code = KAPRODI_CODE_MAPPING.get(prodi_short_name)
if prodi_code:
rule_name = f"Rule Kaprodi {prodi_short_name.upper()}"
clause = f"no_ps = {prodi_code}"
else:
if prodi_short_name: # Only print warning if there is a
name to warn about
print(f"\n- WARNING: No code mapping found for
'{prodi_short_name}'. Skipping role '{role_name}'.")
continue
# --- NEW LOGIC: CREATE OR UPDATE ---
if rule_name:
print(f"\n- Processing rule for role: '{role_name}'")
# This payload will be used for both creating (POST) and
updating (PUT)
payload = {
"name": rule_name,
"filter_type": "Regular",
"clause": clause,
"roles": [role_id],
"tables": all_dataset_ids,
"description": "Automatically created or updated by
Python script."
}
if rule_name in existing_rules_map:
# --- IF RULE EXISTS: PERFORM UPDATE (PUT) ---
rule_id_to_update = existing_rules_map[rule_name]
print(f" -> Rule '{rule_name}' exists (ID:
{rule_id_to_update}). Updating...")
try:
r_update =
session.put(f"{SUPERSET_URL}/api/v1/rowlevelsecurity/{rule_id_to_update}",
json=payload)
if r_update.status_code == 200:
print(f" -> SUCCESS: Rule updated.")
else:
print(f" -> FAILED to update. Status:
{r_update.status_code}, Message: {r_update.text}")
except requests.exceptions.RequestException as e:
print(f" -> FAILED due to an exception: {e}")
else:
# --- IF RULE DOES NOT EXIST: PERFORM CREATE (POST) ---
print(f" -> Rule '{rule_name}' does not exist.
Creating...")
try:
r_create =
session.post(f"{SUPERSET_URL}/api/v1/rowlevelsecurity/", json=payload)
if r_create.status_code == 201:
print(f" -> SUCCESS: Rule created.")
# Add the new rule to the map so we don't try
to re-create it in the same session
new_rule_id = r_create.json().get('id')
if new_rule_id:
existing_rules_map[rule_name] = new_rule_id
else:
print(f" -> FAILED to create. Status:
{r_create.status_code}, Message: {r_create.text}")
except requests.exceptions.RequestException as e:
print(f" -> FAILED due to an exception: {e}")
print("\n4. Process finished.")
if __name__ == "__main__":
main()
i got an error message when try to update rules.
- Processing rule for role: 'Kaprodi Mesin'
-> Rule 'Rule Kaprodi MESIN' exists (ID: 12). Updating...
-> FAILED to update. Status: 201, Message: {
"id": 12,
"result": {
"clause": "no_ps = 131",
"description": "Automatically created or updated by Python script.",
"filter_type": "Regular",
"name": "Rule Kaprodi MESIN",
"roles": [
9
],
"tables": [
25,
20,
11,
17,
12,
10,
18,
2,
15,
13,
21,
5,
19,
24,
8,
6,
16,
4,
23,
1,
22,
3,
14,
9,
7
]
}
}
Where is my fault?
GitHub link: https://github.com/apache/superset/discussions/34546
----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]