Skip to content
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

✨add preference to allow data collections form services #5112

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
bd254f5
refactor tests
Nov 30, 2023
b6850b8
log logs disabling
Nov 30, 2023
5b63f9e
refactor
Nov 30, 2023
94316d4
defined new frontend preference
Nov 30, 2023
aa56b71
connected allow_metrics_collection
Nov 30, 2023
0db7167
added frontend changes
Nov 30, 2023
c29e392
mypy
Nov 30, 2023
ee7d1e2
remove unrequired commad
Dec 1, 2023
6217730
updated texts
Dec 1, 2023
048480d
add support for italic label
Dec 1, 2023
0782226
added missing font
Dec 1, 2023
6f5cfe2
Merge branch 'master' into pr-osparc-disable-user-metrics-via-prefere…
GitHK Dec 1, 2023
705ed2c
Merge remote-tracking branch 'upstream/master' into pr-osparc-disable…
Dec 4, 2023
169b9f8
removed unrequired
Dec 4, 2023
0629f46
Merge branch 'pr-osparc-disable-user-metrics-via-preferences' of gith…
Dec 4, 2023
c99bdb7
Merge branch 'master' into pr-osparc-disable-user-metrics-via-prefere…
GitHK Dec 4, 2023
8fbbd19
refactor tests
Nov 30, 2023
dc8924a
log logs disabling
Nov 30, 2023
25ca2c9
refactor
Nov 30, 2023
e096734
defined new frontend preference
Nov 30, 2023
2f7bf3f
connected allow_metrics_collection
Nov 30, 2023
f74a43f
added frontend changes
Nov 30, 2023
2f40181
mypy
Nov 30, 2023
21f1c96
remove unrequired commad
Dec 1, 2023
b9f73da
updated texts
Dec 1, 2023
cfc839d
add support for italic label
Dec 1, 2023
8e330a2
added missing font
Dec 1, 2023
4c11385
removed unrequired
Dec 4, 2023
3992806
Merge branch 'master' into pr-osparc-disable-user-metrics-via-prefere…
GitHK Dec 5, 2023
a8cee36
@ignapas using font name
Dec 5, 2023
8b791e0
Merge branch 'pr-osparc-disable-user-metrics-via-preferences' of gith…
Dec 5, 2023
77c32c9
Merge branch 'master' into pr-osparc-disable-user-metrics-via-prefere…
GitHK Dec 6, 2023
c7271bd
removed unused
Dec 6, 2023
bd12d74
Merge branch 'pr-osparc-disable-user-metrics-via-preferences' of gith…
Dec 6, 2023
b1bab9d
reverting back required font
Dec 6, 2023
f654ab8
Merge remote-tracking branch 'upstream/master' into pr-osparc-disable…
Dec 6, 2023
fb14b31
updated capitalization
Dec 6, 2023
37184e0
Merge branch 'master' into pr-osparc-disable-user-metrics-via-prefere…
GitHK Dec 11, 2023
1b5e809
Merge branch 'master' into pr-osparc-disable-user-metrics-via-prefere…
GitHK Dec 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from .user_preferences import FrontendUserPreference


class AllowMetricsCollectionFrontendUserPreference(FrontendUserPreference):
preference_identifier: str = "allowMetricsCollection"
GitHK marked this conversation as resolved.
Show resolved Hide resolved
value: bool = True
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async def upsert_projects_networks(
self, project_id: ProjectID, networks_with_aliases: NetworksWithAliases
) -> None:
projects_networks_to_insert = ProjectsNetworks.parse_obj(
dict(project_uuid=project_id, networks_with_aliases=networks_with_aliases)
{"project_uuid": project_id, "networks_with_aliases": networks_with_aliases}
)

async with self.db_engine.acquire() as conn:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from models_library.products import ProductName
from models_library.user_preferences import FrontendUserPreference, PreferenceName
from models_library.users import UserID
from simcore_postgres_database.utils_user_preferences import FrontendUserPreferencesRepo

from ._base import BaseRepository


def _get_user_preference_name(user_id: UserID, preference_name: PreferenceName) -> str:
return f"{user_id}/{preference_name}"


class UserPreferencesFrontendRepository(BaseRepository):
async def get_user_preference(
self,
*,
user_id: UserID,
product_name: ProductName,
preference_class: type[FrontendUserPreference],
) -> FrontendUserPreference | None:
async with self.db_engine.acquire() as conn:
preference_payload: dict | None = await FrontendUserPreferencesRepo.load(
conn,
user_id=user_id,
preference_name=_get_user_preference_name(
user_id, preference_class.get_preference_name()
),
product_name=product_name,
)

return (
None
if preference_payload is None
else preference_class.parse_obj(preference_payload)
)
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
update_service_params_from_settings,
)

log = logging.getLogger(__name__)
_logger = logging.getLogger(__name__)


def extract_service_port_service_settings(
Expand All @@ -42,6 +42,7 @@ def _get_environment_variables(
app_settings: AppSettings,
*,
allow_internet_access: bool,
metrics_collection_allowed: bool,
) -> dict[str, str]:
registry_settings = app_settings.DIRECTOR_V2_DOCKER_REGISTRY
rabbit_settings = app_settings.DIRECTOR_V2_RABBITMQ
Expand All @@ -53,6 +54,16 @@ def _get_environment_variables(
if scheduler_data.paths_mapping.state_exclude is not None:
state_exclude = scheduler_data.paths_mapping.state_exclude

callbacks_mapping: CallbacksMapping = scheduler_data.callbacks_mapping

if not metrics_collection_allowed:
_logger.info(
"user=%s disabled metrics collection, disable prometheus metrics for node_id=%s",
scheduler_data.user_id,
scheduler_data.node_uuid,
)
callbacks_mapping.metrics = None

return {
# These environments will be captured by
# services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/core/settings.py::ApplicationSettings
Expand All @@ -64,7 +75,7 @@ def _get_environment_variables(
"DY_SIDECAR_RUN_ID": scheduler_data.run_id,
"DY_SIDECAR_USER_SERVICES_HAVE_INTERNET_ACCESS": f"{allow_internet_access}",
"DY_SIDECAR_STATE_EXCLUDE": json_dumps(f"{x}" for x in state_exclude),
"DY_SIDECAR_CALLBACKS_MAPPING": scheduler_data.callbacks_mapping.json(),
"DY_SIDECAR_CALLBACKS_MAPPING": callbacks_mapping.json(),
"DY_SIDECAR_STATE_PATHS": json_dumps(
f"{x}" for x in scheduler_data.paths_mapping.state_paths
),
Expand Down Expand Up @@ -139,8 +150,10 @@ def get_dynamic_sidecar_spec(
swarm_network_id: str,
settings: SimcoreServiceSettingsLabel,
app_settings: AppSettings,
*,
has_quota_support: bool,
allow_internet_access: bool,
metrics_collection_allowed: bool,
) -> AioDockerServiceSpec:
"""
The dynamic-sidecar is responsible for managing the lifecycle
Expand Down Expand Up @@ -329,6 +342,7 @@ def get_dynamic_sidecar_spec(
scheduler_data,
app_settings,
allow_internet_access=allow_internet_access,
metrics_collection_allowed=metrics_collection_allowed,
),
"Hosts": [],
"Image": dynamic_sidecar_settings.DYNAMIC_SIDECAR_IMAGE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
are_all_user_services_containers_running,
attach_project_networks,
attempt_pod_removal_and_data_saving,
get_allow_metrics_collection,
get_director_v0_client,
parse_containers_inspect,
prepare_services_environment,
Expand Down Expand Up @@ -183,6 +184,12 @@ async def action(cls, app: FastAPI, scheduler_data: SchedulerData) -> None:
swarm_network_id: NetworkId = swarm_network["Id"]
swarm_network_name: str = swarm_network["Name"]

metrics_collection_allowed: bool = await get_allow_metrics_collection(
app,
user_id=scheduler_data.user_id,
product_name=scheduler_data.product_name,
)

# start dynamic-sidecar and run the proxy on the same node

# Each time a new dynamic-sidecar service is created
Expand All @@ -200,6 +207,7 @@ async def action(cls, app: FastAPI, scheduler_data: SchedulerData) -> None:
app_settings=app.state.settings,
has_quota_support=dynamic_services_scheduler_settings.DYNAMIC_SIDECAR_ENABLE_VOLUME_LIMITS,
allow_internet_access=allow_internet_access,
metrics_collection_allowed=metrics_collection_allowed,
)

catalog_client = CatalogClient.instance(app)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@

import json
import logging
from typing import Any
from typing import Any, cast

from fastapi import FastAPI
from models_library.products import ProductName
from models_library.projects_networks import ProjectsNetworks
from models_library.projects_nodes import NodeID
from models_library.projects_nodes_io import NodeIDStr
from models_library.rabbitmq_messages import InstrumentationRabbitMessage
from models_library.service_settings_labels import SimcoreServiceLabels
from models_library.services import ServiceKeyVersion
from models_library.shared_user_preferences import (
AllowMetricsCollectionFrontendUserPreference,
)
from models_library.sidecar_volumes import VolumeCategory, VolumeStatus
from models_library.user_preferences import FrontendUserPreference
from models_library.users import UserID
from servicelib.fastapi.long_running_tasks.client import (
ProgressCallback,
TaskClientResultError,
Expand Down Expand Up @@ -40,6 +46,9 @@
from ....api_keys_manager import safe_remove
from ....db.repositories.projects import ProjectsRepository
from ....db.repositories.projects_networks import ProjectsNetworksRepository
from ....db.repositories.user_preferences_frontend import (
UserPreferencesFrontendRepository,
)
from ....director_v0 import DirectorV0Client
from ...api_client import (
BaseClientHTTPError,
Expand Down Expand Up @@ -442,3 +451,24 @@ async def prepare_services_environment(
)

scheduler_data.dynamic_sidecar.is_service_environment_ready = True


async def get_allow_metrics_collection(
app: FastAPI, user_id: UserID, product_name: ProductName
) -> bool:
repo = get_repository(app, UserPreferencesFrontendRepository)
preference: FrontendUserPreference | None = await repo.get_user_preference(
user_id=user_id,
product_name=product_name,
preference_class=AllowMetricsCollectionFrontendUserPreference,
)

if preference is None:
return cast(
bool, AllowMetricsCollectionFrontendUserPreference.get_default_value()
GitHK marked this conversation as resolved.
Show resolved Hide resolved
)

allow_metrics_collection = AllowMetricsCollectionFrontendUserPreference.parse_obj(
GitHK marked this conversation as resolved.
Show resolved Hide resolved
preference
)
return cast(bool, allow_metrics_collection.value)
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def test_dynamic_sidecar_env_vars(
scheduler_data_from_http_request,
app_settings,
allow_internet_access=False,
metrics_collection_allowed=True,
GitHK marked this conversation as resolved.
Show resolved Hide resolved
)
print("dynamic_sidecar_env_vars:", dynamic_sidecar_env_vars)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ def test_get_dynamic_proxy_spec(
app_settings=minimal_app.state.settings,
has_quota_support=False,
allow_internet_access=False,
metrics_collection_allowed=True,
)

exclude_keys: Mapping[int | str, Any] = {
Expand Down Expand Up @@ -508,6 +509,7 @@ async def test_merge_dynamic_sidecar_specs_with_user_specific_specs(
app_settings=minimal_app.state.settings,
has_quota_support=False,
allow_internet_access=False,
metrics_collection_allowed=True,
)
assert dynamic_sidecar_spec
dynamic_sidecar_spec_dict = dynamic_sidecar_spec.dict()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ qx.Class.define("osparc.Preferences", {
init: 4,
event: "changeJobConcurrencyLimit",
apply: "__patchPreference"
},

allowMetricsCollection: {
nullable: false,
init: true,
check: "Boolean",
event: "changeAllowMetricsCollection",
apply: "__patchPreference"
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ qx.Class.define("osparc.desktop.preferences.pages.BasePage", {
/**
* Common layout for tooltip label
*/
_createHelpLabel: function(message=null) {
_createHelpLabel: function(message=null, font="text-13") {
const label = new qx.ui.basic.Label().set({
value: message,
alignX: "left",
rich: true,
font: "text-13"
font: font
});
return label;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ qx.Class.define("osparc.desktop.preferences.pages.GeneralPage", {
const title = this.tr("General Settings");
this.base(arguments, title, iconSrc);

const walletIndicatorSettings = this.__createCreditsIndicatorSettings();
this.add(walletIndicatorSettings);

this.add(this.__createCreditsIndicatorSettings());
this.add(this.__createInactivitySetting());
this.add(this.__createJobConcurrencySetting());
this.add(this.__createUserPrivacySettings());
},

statics: {
Expand Down Expand Up @@ -57,11 +56,6 @@ qx.Class.define("osparc.desktop.preferences.pages.GeneralPage", {
// layout
const box = this._createSectionBox(this.tr("Credits Indicator"));

const label = this._createHelpLabel(this.tr(
"Choose when you want the Credits Indicator to be shown in the navigation bar:"
));
box.add(label);

const form = new qx.ui.form.Form();

const preferencesSettings = osparc.Preferences.getInstance();
Expand Down Expand Up @@ -89,7 +83,7 @@ qx.Class.define("osparc.desktop.preferences.pages.GeneralPage", {
const selectable = e.getData();
this.self().patchPreference("walletIndicatorVisibility", walletIndicatorVisibilitySB, selectable.getModel());
});
form.add(walletIndicatorVisibilitySB, this.tr("Show it"));
form.add(walletIndicatorVisibilitySB, this.tr("Show indicator"));

const creditsWarningThresholdField = new qx.ui.form.Spinner().set({
minimum: 100,
Expand All @@ -99,15 +93,15 @@ qx.Class.define("osparc.desktop.preferences.pages.GeneralPage", {
});
preferencesSettings.bind("creditsWarningThreshold", creditsWarningThresholdField, "value");
creditsWarningThresholdField.addListener("changeValue", e => this.self().patchPreference("creditsWarningThreshold", creditsWarningThresholdField, e.getData()));
form.add(creditsWarningThresholdField, this.tr("Warning threshold"));
form.add(creditsWarningThresholdField, this.tr("Show warning when credits below"));

box.add(new qx.ui.form.renderer.Single(form));

return box;
},
__createInactivitySetting: function() {
const box = this._createSectionBox(this.tr("Inactivity shutdown"));
const label = this._createHelpLabel(this.tr("Choose after how long should inactive studies be closed. A value of zero disables this function."));
const box = this._createSectionBox(this.tr("Automatic Shutdown of Idle Instances"));
GitHK marked this conversation as resolved.
Show resolved Hide resolved
const label = this._createHelpLabel(this.tr("Enter 0 to disable this function"), "text-13-italic");
GitHK marked this conversation as resolved.
Show resolved Hide resolved
box.add(label);
const form = new qx.ui.form.Form();
const inactivitySpinner = new qx.ui.form.Spinner().set({
Expand All @@ -126,9 +120,7 @@ qx.Class.define("osparc.desktop.preferences.pages.GeneralPage", {
return box;
},
__createJobConcurrencySetting: function() {
const box = this._createSectionBox(this.tr("Job concurrency"));
const label = this._createHelpLabel(this.tr("Choose how many jobs can run at the same time."));
box.add(label);
const box = this._createSectionBox(this.tr("Job Concurrency"));
const form = new qx.ui.form.Form();
const jobConcurrencySpinner = new qx.ui.form.Spinner().set({
minimum: 1,
Expand All @@ -140,8 +132,23 @@ qx.Class.define("osparc.desktop.preferences.pages.GeneralPage", {
const preferences = osparc.Preferences.getInstance();
preferences.bind("jobConcurrencyLimit", jobConcurrencySpinner, "value");
jobConcurrencySpinner.addListener("changeValue", e => this.self().patchPreference("jobConcurrencyLimit", jobConcurrencySpinner, e.getData()));
form.add(jobConcurrencySpinner, this.tr("Maximum concurrent jobs"));
form.add(jobConcurrencySpinner, this.tr("Maximum number of concurrent jobs"));
box.add(new qx.ui.form.renderer.Single(form));
return box;
},
__createUserPrivacySettings: function() {
const box = this._createSectionBox("Privacy Settings");

const label = this._createHelpLabel(this.tr("Help us improve Sim4Life user experience"), "text-13-italic");
GitHK marked this conversation as resolved.
Show resolved Hide resolved
box.add(label);

const preferencesSettings = osparc.Preferences.getInstance();

const cbAllowMetricsCollection = new qx.ui.form.CheckBox(this.tr("Share usage data"));
preferencesSettings.bind("allowMetricsCollection", cbAllowMetricsCollection, "value");
cbAllowMetricsCollection.addListener("changeValue", e => this.self().patchPreference("allowMetricsCollection", cbAllowMetricsCollection, e.getData()));
box.add(cbAllowMetricsCollection);

return box;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ qx.Theme.define("osparc.theme.Font", {
size: 13
},

"text-13-italic": {
include: "defaults",
size: 13,
italic: true
},

"text-12": {
include: "defaults",
size: 12
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from aiohttp import web
from models_library.products import ProductName
from models_library.user_preferences import AnyUserPreference, PreferenceName
from models_library.user_preferences import FrontendUserPreference, PreferenceName
from models_library.users import UserID
from simcore_postgres_database.utils_user_preferences import FrontendUserPreferencesRepo

Expand All @@ -16,8 +16,8 @@ async def get_user_preference(
*,
user_id: UserID,
product_name: ProductName,
preference_class: type[AnyUserPreference],
) -> AnyUserPreference | None:
preference_class: type[FrontendUserPreference],
) -> FrontendUserPreference | None:
async with get_database_engine(app).acquire() as conn:
preference_payload: dict | None = await FrontendUserPreferencesRepo.load(
conn,
Expand All @@ -40,7 +40,7 @@ async def set_user_preference(
*,
user_id: UserID,
product_name: ProductName,
preference: AnyUserPreference,
preference: FrontendUserPreference,
) -> None:
async with get_database_engine(app).acquire() as conn:
await FrontendUserPreferencesRepo.save(
Expand Down
Loading
Loading