feat: apply workspace specific tags only to some workspaces (#4107)

This commit is contained in:
HugoCasa
2024-07-23 19:12:11 +02:00
committed by GitHub
parent 211e80b69e
commit 609e5d00eb
10 changed files with 119 additions and 42 deletions
+17 -12
View File
@@ -23,11 +23,11 @@ use windmill_common::ee::schedule_key_renewal;
use windmill_common::{
global_settings::{
BASE_URL_SETTING, BUNFIG_INSTALL_SCOPES_SETTING, CRITICAL_ERROR_CHANNELS_SETTING,
CUSTOM_TAGS_SETTING, DEFAULT_TAGS_PER_WORKSPACE_SETTING, ENV_SETTINGS,
EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING, EXTRA_PIP_INDEX_URL_SETTING,
HUB_BASE_URL_SETTING, JOB_DEFAULT_TIMEOUT_SECS_SETTING, JWT_SECRET_SETTING,
KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, NPM_CONFIG_REGISTRY_SETTING, OAUTH_SETTING,
PIP_INDEX_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
CUSTOM_TAGS_SETTING, DEFAULT_TAGS_PER_WORKSPACE_SETTING, DEFAULT_TAGS_WORKSPACES_SETTING,
ENV_SETTINGS, EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING,
EXTRA_PIP_INDEX_URL_SETTING, HUB_BASE_URL_SETTING, JOB_DEFAULT_TIMEOUT_SECS_SETTING,
JWT_SECRET_SETTING, KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, NPM_CONFIG_REGISTRY_SETTING,
OAUTH_SETTING, PIP_INDEX_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING,
SAML_METADATA_SETTING, SCIM_TOKEN_SETTING,
},
@@ -61,11 +61,11 @@ use windmill_worker::{
use crate::monitor::{
initial_load, load_keep_job_dir, load_metrics_debug_enabled, load_require_preexisting_user,
load_tag_per_workspace_enabled, monitor_db, monitor_pool, reload_base_url_setting,
reload_bunfig_install_scopes_setting, reload_critical_error_channels_setting,
reload_extra_pip_index_url_setting, reload_hub_base_url_setting,
reload_job_default_timeout_setting, reload_jwt_secret_setting, reload_license_key,
reload_npm_config_registry_setting, reload_pip_index_url_setting,
load_tag_per_workspace_enabled, load_tag_per_workspace_workspaces, monitor_db, monitor_pool,
reload_base_url_setting, reload_bunfig_install_scopes_setting,
reload_critical_error_channels_setting, reload_extra_pip_index_url_setting,
reload_hub_base_url_setting, reload_job_default_timeout_setting, reload_jwt_secret_setting,
reload_license_key, reload_npm_config_registry_setting, reload_pip_index_url_setting,
reload_retention_period_setting, reload_scim_token_setting, reload_server_config,
reload_worker_config,
};
@@ -365,7 +365,7 @@ Windmill Community Edition {GIT_VERSION}
#[cfg(feature = "tantivy")]
let should_index_jobs =
mode == Mode::Indexer || (enable_standalone_indexer && mode == Mode::Standalone);
mode == Mode::Indexer || (enable_standalone_indexer && mode == Mode::Standalone);
#[cfg(not(feature = "tantivy"))]
let should_index_jobs = false;
@@ -504,9 +504,14 @@ Windmill Community Edition {GIT_VERSION}
},
DEFAULT_TAGS_PER_WORKSPACE_SETTING => {
if let Err(e) = load_tag_per_workspace_enabled(&db).await {
tracing::error!("Error loading default tag per workpsace: {e:#}");
tracing::error!("Error loading default tag per workspace: {e:#}");
}
},
DEFAULT_TAGS_WORKSPACES_SETTING => {
if let Err(e) = load_tag_per_workspace_workspaces(&db).await {
tracing::error!("Error loading default tag per workspace workspaces: {e:#}");
}
}
RETENTION_PERIOD_SECS_SETTING => {
reload_retention_period_setting(&db).await
},
+33 -6
View File
@@ -28,10 +28,11 @@ use windmill_common::{
flow_status::FlowStatusModule,
global_settings::{
BASE_URL_SETTING, BUNFIG_INSTALL_SCOPES_SETTING, CRITICAL_ERROR_CHANNELS_SETTING,
DEFAULT_TAGS_PER_WORKSPACE_SETTING, EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING,
EXTRA_PIP_INDEX_URL_SETTING, HUB_BASE_URL_SETTING, JOB_DEFAULT_TIMEOUT_SECS_SETTING,
JWT_SECRET_SETTING, KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, NPM_CONFIG_REGISTRY_SETTING,
OAUTH_SETTING, PIP_INDEX_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
DEFAULT_TAGS_PER_WORKSPACE_SETTING, DEFAULT_TAGS_WORKSPACES_SETTING,
EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING, EXTRA_PIP_INDEX_URL_SETTING,
HUB_BASE_URL_SETTING, JOB_DEFAULT_TIMEOUT_SECS_SETTING, JWT_SECRET_SETTING,
KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, NPM_CONFIG_REGISTRY_SETTING, OAUTH_SETTING,
PIP_INDEX_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING,
SAML_METADATA_SETTING, SCIM_TOKEN_SETTING,
},
@@ -41,8 +42,8 @@ use windmill_common::{
users::truncate_token,
utils::{now_from_db, rd_string},
worker::{
load_worker_config, reload_custom_tags_setting, DEFAULT_TAGS_PER_WORKSPACE, SERVER_CONFIG,
WORKER_CONFIG,
load_worker_config, reload_custom_tags_setting, DEFAULT_TAGS_PER_WORKSPACE,
DEFAULT_TAGS_WORKSPACES, SERVER_CONFIG, WORKER_CONFIG,
},
BASE_URL, CRITICAL_ERROR_CHANNELS, DB, DEFAULT_HUB_BASE_URL, HUB_BASE_URL,
METRICS_DEBUG_ENABLED, METRICS_ENABLED,
@@ -127,6 +128,10 @@ pub async fn initial_load(
tracing::error!("Error loading default tag per workpsace: {e:#}");
}
if let Err(e) = load_tag_per_workspace_workspaces(db).await {
tracing::error!("Error loading default tag per workpsace workspaces: {e:#}");
}
if server_mode {
load_require_preexisting_user(db).await;
}
@@ -204,6 +209,28 @@ pub async fn load_tag_per_workspace_enabled(db: &DB) -> error::Result<()> {
Ok(())
}
pub async fn load_tag_per_workspace_workspaces(db: &DB) -> error::Result<()> {
let workspaces = load_value_from_global_settings(db, DEFAULT_TAGS_WORKSPACES_SETTING).await;
match workspaces {
Ok(Some(serde_json::Value::Array(t))) => {
let workspaces = t
.iter()
.filter_map(|x| x.as_str())
.map(|x| x.to_string())
.collect::<Vec<String>>();
let mut w = DEFAULT_TAGS_WORKSPACES.write().await;
*w = Some(workspaces);
}
Ok(None) => {
let mut w = DEFAULT_TAGS_WORKSPACES.write().await;
*w = None;
}
_ => (),
};
Ok(())
}
pub async fn load_metrics_debug_enabled(db: &DB) -> error::Result<()> {
let metrics_enabled = load_value_from_global_settings(db, EXPOSE_DEBUG_METRICS_SETTING).await;
match metrics_enabled {
@@ -1,5 +1,6 @@
pub const CUSTOM_TAGS_SETTING: &str = "custom_tags";
pub const DEFAULT_TAGS_PER_WORKSPACE_SETTING: &str = "default_tags_per_workspace";
pub const DEFAULT_TAGS_WORKSPACES_SETTING: &str = "default_tags_workspaces";
pub const BASE_URL_SETTING: &str = "base_url";
pub const OAUTH_SETTING: &str = "oauths";
pub const RETENTION_PERIOD_SECS_SETTING: &str = "retention_period_secs";
+1
View File
@@ -43,6 +43,7 @@ lazy_static::lazy_static! {
];
pub static ref DEFAULT_TAGS_PER_WORKSPACE: AtomicBool = AtomicBool::new(false);
pub static ref DEFAULT_TAGS_WORKSPACES: Arc<RwLock<Option<Vec<String>>>> = Arc::new(RwLock::new(None));
pub static ref WORKER_CONFIG: Arc<RwLock<WorkerConfig>> = Arc::new(RwLock::new(WorkerConfig {
+10 -2
View File
@@ -63,7 +63,9 @@ use windmill_common::{
scripts::{get_full_hub_script_by_path, ScriptHash, ScriptLang},
users::{SUPERADMIN_NOTIFICATION_EMAIL, SUPERADMIN_SECRET_EMAIL},
utils::{not_found_if_none, report_critical_error, StripPath},
worker::{to_raw_value, DEFAULT_TAGS_PER_WORKSPACE, NO_LOGS, WORKER_CONFIG},
worker::{
to_raw_value, DEFAULT_TAGS_PER_WORKSPACE, DEFAULT_TAGS_WORKSPACES, NO_LOGS, WORKER_CONFIG,
},
BASE_URL, DB, METRICS_ENABLED,
};
@@ -3640,7 +3642,13 @@ pub async fn push<'c, 'd, R: rsmq_async::RsmqConnection + Send + 'c>(
.map(|e| (Some(e.0), e.1))
.unwrap_or_else(|| (None, None));
let per_workspace: bool = DEFAULT_TAGS_PER_WORKSPACE.load(std::sync::atomic::Ordering::Relaxed);
let per_workspace_workspaces = DEFAULT_TAGS_WORKSPACES.read().await;
let per_workspace = DEFAULT_TAGS_PER_WORKSPACE.load(std::sync::atomic::Ordering::Relaxed)
&& (per_workspace_workspaces.is_none()
|| per_workspace_workspaces
.as_ref()
.unwrap()
.contains(&workspace_id.to_string()));
let tag = if dedicated_worker.is_some_and(|x| x) {
format!(
@@ -6,6 +6,7 @@
import DefaultTagsInner from './DefaultTagsInner.svelte'
export let defaultTagPerWorkspace: boolean | undefined = undefined
export let defaultTagWorkspaces: string[] | undefined = undefined
let placement: 'bottom-end' | 'top-end' = 'bottom-end'
</script>
@@ -24,5 +25,5 @@
>
</Button>
</svelte:fragment>
<DefaultTagsInner bind:defaultTagPerWorkspace />
<DefaultTagsInner bind:defaultTagPerWorkspace bind:defaultTagWorkspaces />
</Popup>
@@ -1,25 +1,39 @@
<script lang="ts">
import { Button } from './common'
import { AlertTriangle, Loader2 } from 'lucide-svelte'
import { SettingService, WorkerService } from '$lib/gen'
import { SettingService, WorkerService, WorkspaceService } from '$lib/gen'
import Tooltip from './Tooltip.svelte'
import { sendUserToast } from '$lib/toast'
import { enterpriseLicense, superadmin } from '$lib/stores'
import { DEFAULT_TAGS_PER_WORKSPACE_SETTING } from '$lib/consts'
import { DEFAULT_TAGS_PER_WORKSPACE_SETTING, DEFAULT_TAGS_WORKSPACES_SETTING } from '$lib/consts'
import Toggle from './Toggle.svelte'
import MultiSelectWrapper from './multiselect/MultiSelectWrapper.svelte'
let defaultTags: string[] | undefined = undefined
export let defaultTagPerWorkspace: boolean | undefined = undefined
export let defaultTagWorkspaces: string[] | undefined = undefined
let limitToWorkspaces = false
let workspaces: string[] = []
async function loadWorkspaces() {
workspaces = (await WorkspaceService.listWorkspacesAsSuperAdmin()).map((m) => m.id)
}
async function loadDefaultTags() {
try {
defaultTags = (await WorkerService.geDefaultTags()) ?? []
defaultTagWorkspaces =
((await SettingService.getGlobal({
key: DEFAULT_TAGS_WORKSPACES_SETTING
})) as any) ?? []
limitToWorkspaces = defaultTagWorkspaces ? defaultTagWorkspaces.length > 0 : false
} catch (err) {
sendUserToast(`Could not load default tags: ${err}`, true)
}
}
loadDefaultTags()
loadWorkspaces()
</script>
<div class="flex flex-col w-80 p-2 gap-2">
@@ -48,11 +62,17 @@
</div>
{/each}
</div>
<div class="py-4">
<div class="py-4 flex flex-col gap-2">
<Toggle
bind:checked={defaultTagPerWorkspace}
options={{ right: 'workspace specific default tags' }}
/>
{#if defaultTagPerWorkspace}
<Toggle bind:checked={limitToWorkspaces} options={{ right: 'only for some workspaces' }} />
{#if limitToWorkspaces}
<MultiSelectWrapper items={workspaces} bind:value={defaultTagWorkspaces} />
{/if}
{/if}
</div>
<Button
variant="contained"
@@ -65,6 +85,15 @@
value: defaultTagPerWorkspace
}
})
await SettingService.setGlobal({
key: DEFAULT_TAGS_WORKSPACES_SETTING,
requestBody: {
value:
limitToWorkspaces && defaultTagWorkspaces && defaultTagWorkspaces.length > 0
? defaultTagWorkspaces
: undefined
}
})
loadDefaultTags()
sendUserToast('Saved')
}}
@@ -327,17 +327,17 @@
size="xs"
on:click={() => {
if (nconfig != undefined) {
nconfig.worker_tags = defaultTagPerWorkspace
? defaultTags.concat(nativeTags).map((nt) => `${nt}-${workspaceTag}`)
: defaultTags.concat(nativeTags)
nconfig.worker_tags =
defaultTagPerWorkspace && workspaceTag
? defaultTags.concat(nativeTags).map((nt) => `${nt}-${workspaceTag}`)
: defaultTags.concat(nativeTags)
dirty = true
}
}}
disabled={defaultTagPerWorkspace && !workspaceTag}
>
Reset to all tags <Tooltip
>{(defaultTagPerWorkspace
>{(defaultTagPerWorkspace && workspaceTag
? defaultTags.concat(nativeTags).map((nt) => `${nt}-${workspaceTag}`)
: defaultTags.concat(nativeTags)
).join(', ')}</Tooltip
@@ -349,13 +349,13 @@
size="xs"
on:click={() => {
if (nconfig != undefined) {
nconfig.worker_tags = defaultTagPerWorkspace
? defaultTags.map((nt) => `${nt}-${workspaceTag}`)
: defaultTags
nconfig.worker_tags =
defaultTagPerWorkspace && workspaceTag
? defaultTags.map((nt) => `${nt}-${workspaceTag}`)
: defaultTags
dirty = true
}
}}
disabled={defaultTagPerWorkspace && !workspaceTag}
>
Reset to all tags minus native ones <Tooltip
>{(defaultTagPerWorkspace
@@ -370,16 +370,16 @@
size="xs"
on:click={() => {
if (nconfig != undefined) {
nconfig.worker_tags = defaultTagPerWorkspace
? nativeTags.map((nt) => `${nt}-${workspaceTag}`)
: nativeTags
nconfig.worker_tags =
defaultTagPerWorkspace && workspaceTag
? nativeTags.map((nt) => `${nt}-${workspaceTag}`)
: nativeTags
dirty = true
}
}}
disabled={defaultTagPerWorkspace && !workspaceTag}
>
Reset to native tags <Tooltip
>{(defaultTagPerWorkspace
>{(defaultTagPerWorkspace && workspaceTag
? nativeTags.map((nt) => `${nt}-${workspaceTag}`)
: nativeTags
).join(', ')}</Tooltip
@@ -392,8 +392,7 @@
noInputStyles
hideArrow={true}
items={workspaces.map((w) => w.id)}
inputClassName={'flex !font-gray-600 !font-primary !bg-surface-primary ' +
(!workspaceTag ? '!border-red-600/60 !dark:border-red-400/70' : '')}
inputClassName={'flex !font-gray-600 !font-primary !bg-surface-primary'}
dropdownClassName="!text-sm !py-2 !rounded-sm !border-gray-200 !border !shadow-md"
className="!font-gray-600 !font-primary !bg-surface-primary"
create
+1
View File
@@ -38,6 +38,7 @@ export const SCRIPT_CUSTOMISE_SHOW_KIND = true
export const WORKER_S3_BUCKET_SYNC_SETTING = 'worker_s3_bucket_sync'
export const CUSTOM_TAGS_SETTING = 'custom_tags'
export const DEFAULT_TAGS_PER_WORKSPACE_SETTING = 'default_tags_per_workspace'
export const DEFAULT_TAGS_WORKSPACES_SETTING = 'default_tags_workspaces'
export const WORKSPACE_SLACK_BOT_TOKEN_PATH = 'f/slack_bot/bot_token'
@@ -14,7 +14,7 @@
import Head from '$lib/components/table/Head.svelte'
import Tooltip from '$lib/components/Tooltip.svelte'
import WorkspaceGroup from '$lib/components/WorkspaceGroup.svelte'
import { WorkerService, type WorkerPing, ConfigService } from '$lib/gen'
import { WorkerService, type WorkerPing, ConfigService, SettingService } from '$lib/gen'
import { enterpriseLicense, superadmin } from '$lib/stores'
import { sendUserToast } from '$lib/toast'
import { displayDate, groupBy, pluralize, truncate } from '$lib/utils'
@@ -23,6 +23,7 @@
import AutoComplete from 'simple-svelte-autocomplete'
import YAML from 'yaml'
import { DEFAULT_TAGS_WORKSPACES_SETTING } from '$lib/consts'
let workers: WorkerPing[] | undefined = undefined
let workerGroups: Record<string, any> | undefined = undefined
@@ -90,9 +91,13 @@
}
let defaultTagPerWorkspace: boolean | undefined = undefined
let defaultTagWorkspaces: string[] | undefined = undefined
async function loadDefaultTagsPerWorkspace() {
try {
defaultTagPerWorkspace = await WorkerService.isDefaultTagsPerWorkspace()
defaultTagWorkspaces = (await SettingService.getGlobal({
key: DEFAULT_TAGS_WORKSPACES_SETTING
})) as any
} catch (err) {
sendUserToast(`Could not load default tag per workspace setting: ${err}`, true)
}
@@ -271,7 +276,7 @@
/>
</div>
<div>
<DefaultTags bind:defaultTagPerWorkspace />
<DefaultTags bind:defaultTagPerWorkspace bind:defaultTagWorkspaces />
</div>
<div>
<Button