Skip to content

Commit

Permalink
WIP investigating problem and possible solutions
Browse files Browse the repository at this point in the history
  • Loading branch information
fisjac committed Sep 27, 2024
1 parent de3af85 commit 54f044b
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,9 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
const [importingModal, setImportingModal] = useState<boolean>(false);
const [importingErrorMessage, setImportingErrorMessage] = useState<string>();
const [passwordFields, setPasswordFields] = useState<string[]>([]);
const [encryptedExtraFields, setEncryptedExtraFields] = useState<string[]>(
[],
);
const [sshTunnelPasswordFields, setSSHTunnelPasswordFields] = useState<
string[]
>([]);
Expand Down Expand Up @@ -1342,6 +1345,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
const onDbImport = async (info: UploadChangeParam) => {
setImportingErrorMessage('');
setPasswordFields([]);
setEncryptedExtraFields([]);
setSSHTunnelPasswordFields([]);
setSSHTunnelPrivateKeyFields([]);
setSSHTunnelPrivateKeyPasswordFields([]);
Expand Down
4 changes: 4 additions & 0 deletions superset-frontend/src/views/CRUD/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
createErrorHandler,
getAlreadyExists,
getPasswordsNeeded,
getEncryptedExtraNeeded,
hasTerminalValidation,
getSSHPasswordsNeeded,
getSSHPrivateKeysNeeded,
Expand Down Expand Up @@ -400,6 +401,7 @@ export function useSingleViewResource<D extends object = any>(
interface ImportResourceState {
loading: boolean;
passwordsNeeded: string[];
encryptedExtraNeeded: string[];
alreadyExists: string[];
sshPasswordNeeded: string[];
sshPrivateKeyNeeded: string[];
Expand All @@ -415,6 +417,7 @@ export function useImportResource(
const [state, setState] = useState<ImportResourceState>({
loading: false,
passwordsNeeded: [],
encryptedExtraNeeded: [],
alreadyExists: [],
sshPasswordNeeded: [],
sshPrivateKeyNeeded: [],
Expand Down Expand Up @@ -533,6 +536,7 @@ export function useImportResource(
} else {
updateState({
passwordsNeeded: getPasswordsNeeded(error.errors),
encryptedExtraNeeded: getEncryptedExtraNeeded(error.errors),
sshPasswordNeeded: getSSHPasswordsNeeded(error.errors),
sshPrivateKeyNeeded: getSSHPrivateKeysNeeded(error.errors),
sshPrivateKeyPasswordNeeded: getSSHPrivateKeyPasswordsNeeded(
Expand Down
18 changes: 18 additions & 0 deletions superset-frontend/src/views/CRUD/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,14 @@ const isNeedsPassword = (payload: any) =>
(e: string) => e === 'Must provide a password for the database',
);

export /* eslint-disable no-underscore-dangle */
const isNeedsEncryptedExtra = (payload: any) =>
typeof payload === 'object' &&
Array.isArray(payload._schema) &&
!!payload._schema?.find(
(e: string) => e === 'Must provide encrypted credentials for the database',
);

export /* eslint-disable no-underscore-dangle */
const isNeedsSSHPassword = (payload: any) =>
typeof payload === 'object' &&
Expand Down Expand Up @@ -433,6 +441,15 @@ export const getPasswordsNeeded = (errors: Record<string, any>[]) =>
)
.flat();

export const getEncryptedExtraNeeded = (errors: Record<string, any>[]) =>
errors
.map(error =>
Object.entries(error.extra)
.filter(([, payload]) => isNeedsEncryptedExtra(payload))
.map(([fileName]) => fileName),
)
.flat();

export const getSSHPasswordsNeeded = (errors: Record<string, any>[]) =>
errors
.map(error =>
Expand Down Expand Up @@ -482,6 +499,7 @@ export const hasTerminalValidation = (errors: Record<string, any>[]) =>
return !noIssuesCodes.every(
([, payload]) =>
isNeedsPassword(payload) ||
isNeedsEncryptedExtra(payload) ||
isAlreadyExists(payload) ||
isNeedsSSHPassword(payload) ||
isNeedsSSHPrivateKey(payload) ||
Expand Down
9 changes: 9 additions & 0 deletions superset/commands/chart/importers/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.

import logging
from typing import Any

from marshmallow import Schema
Expand All @@ -31,6 +32,8 @@
from superset.databases.schemas import ImportV1DatabaseSchema
from superset.datasets.schemas import ImportV1DatasetSchema

logger = logging.getLogger(__name__)


class ImportChartsCommand(ImportModelsCommand):
"""Import charts"""
Expand All @@ -49,22 +52,28 @@ class ImportChartsCommand(ImportModelsCommand):
def _import(configs: dict[str, Any], overwrite: bool = False) -> None:
# discover datasets associated with charts
dataset_uuids: set[str] = set()
logger.info("parsing datasets")
for file_name, config in configs.items():
if file_name.startswith("charts/"):
dataset_uuids.add(config["dataset_uuid"])
logger.info("datasets parsed: %s", dataset_uuids)

# discover databases associated with datasets
logger.info("discovering databases associated with datasets")

database_uuids: set[str] = set()
for file_name, config in configs.items():
if file_name.startswith("datasets/") and config["uuid"] in dataset_uuids:
database_uuids.add(config["database_uuid"])

# import related databases
logger.info("importing related dbs")
database_ids: dict[str, int] = {}
for file_name, config in configs.items():
if file_name.startswith("databases/") and config["uuid"] in database_uuids:
database = import_database(config, overwrite=False)
database_ids[str(database.uuid)] = database.id
logger.info("related dbs: %s", database_ids)

# import datasets with the correct parent ref
datasets: dict[str, SqlaTable] = {}
Expand Down
4 changes: 4 additions & 0 deletions superset/commands/importers/v1/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ def load_configs(
db_ssh_tunnel_priv_key_passws[config["uuid"]]
)

logger.info(
"attempting to load content into schema %s %s", schema, content
)

schema.load(config)
configs[file_name] = config
except ValidationError as exc:
Expand Down
16 changes: 16 additions & 0 deletions superset/databases/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from __future__ import annotations

import inspect
import logging
import os
from pathlib import Path
from typing import Any, TypedDict
Expand Down Expand Up @@ -55,6 +56,8 @@
from superset.utils import json
from superset.utils.core import markdown, parse_ssl_cert

logger = logging.getLogger(__name__)

database_schemas_query_schema = {
"type": "object",
"properties": {
Expand Down Expand Up @@ -859,6 +862,7 @@ def fix_allow_csv_upload(
allow_csv_upload = fields.Boolean()
impersonate_user = fields.Boolean()
extra = fields.Nested(ImportV1DatabaseExtraSchema)
encrypted_extra = fields.String(allow_none=True)
uuid = fields.UUID(required=True)
version = fields.String(required=True)
is_managed_externally = fields.Boolean(allow_none=True, dump_default=False)
Expand All @@ -878,6 +882,18 @@ def validate_password(self, data: dict[str, Any], **kwargs: Any) -> None:
if password == PASSWORD_MASK and data.get("password") is None:
raise ValidationError("Must provide a password for the database")

@validates_schema
def validate_encrypted_extra(self, data: dict[str, Any], **kwargs: Any) -> None:
"""If encrypted extra contains masked data, encrypted extra is required"""
uuid = data["uuid"]
existing = db.session.query(Database).filter_by(uuid=uuid).first()
if existing:
return
encrypted_extra = data.get("encrypted_extra", None)
logger.info("encrypted_extra loaded as %s", encrypted_extra)
if not encrypted_extra:
raise ValidationError("Must provide encrypted credentials for the database")

@validates_schema
def validate_ssh_tunnel_credentials(
self, data: dict[str, Any], **kwargs: Any
Expand Down
1 change: 1 addition & 0 deletions superset/models/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class Database(Model, AuditMixinNullable, ImportExportMixin): # pylint: disable
"allow_file_upload",
"extra",
"impersonate_user",
"encrypted_extra",
]
extra_import_fields = [
"password",
Expand Down

0 comments on commit 54f044b

Please sign in to comment.