Skip to content

Commit

Permalink
fix: prevent multiple samba providers on same node (#765)
Browse files Browse the repository at this point in the history
  • Loading branch information
andre8244 authored Dec 12, 2024
1 parent e0239c6 commit c3f943c
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 66 deletions.
4 changes: 3 additions & 1 deletion core/ui/public/i18n/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,9 @@
"open_users_admin_portal": "Open user portal",
"users_admin_page_tooltips": "User portal permits domain users to change their own password. The portal is accessible to users also on any node running the domain provider replica. The generic URL is https://{node_fqdn_or_ip}/users-admin/{domain}/",
"users_admin_page_description": "User administration self service portal",
"host_format": "Must be a valid domain name or IP address"
"host_format": "Must be a valid domain name or IP address",
"provider_already_installed": "Provider already installed",
"no_node_eligible_for_provider_installation": "No node is eligible for provider installation"
},
"samba": {
"adminuser": "Samba admin username",
Expand Down
46 changes: 44 additions & 2 deletions core/ui/src/components/domains/AddInternalProviderModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,28 @@
}}</template>
<template slot="content">
<template v-if="step == 'node'">
<!-- //// disable unavailable nodes -->
<div>
{{ $t("domains.choose_node_for_account_provider_installation") }}
</div>
<NodeSelector @selectNode="onSelectNode" class="mg-top-xlg" />
<NsInlineNotification
v-if="clusterNodes.length == disabledNodes.length"
kind="info"
:title="$t('domains.no_node_eligible_for_provider_installation')"
:showCloseButton="false"
/>
<NodeSelector
:disabledNodes="disabledNodes"
@selectNode="onSelectNode"
class="mg-top-xlg"
>
<template v-for="node in clusterNodes">
<template :slot="`node-${node.id}`">
<span v-if="disabledNodes.includes(node.id)" :key="node.id">
{{ $t("domains.provider_already_installed") }}
</span>
</template>
</template>
</NodeSelector>
</template>
<template v-if="step == 'installingProvider'">
<NsInlineNotification
Expand Down Expand Up @@ -242,6 +259,7 @@ import {
} from "@nethserver/ns8-ui-lib";
import to from "await-to-js";
import NodeSelector from "@/components/nodes/NodeSelector";
import { mapState } from "vuex";

export default {
name: "AddInternalProviderModal",
Expand All @@ -264,6 +282,10 @@ export default {
type: String,
default: "",
},
domains: {
type: Array,
default: () => [],
},
},
data() {
return {
Expand Down Expand Up @@ -315,6 +337,7 @@ export default {
};
},
computed: {
...mapState(["clusterNodes"]),
isOpenLdap() {
return this.domain.schema == "rfc2307";
},
Expand Down Expand Up @@ -359,6 +382,25 @@ export default {
return this.samba.ipAddressOptions;
}
},
disabledNodes() {
if (this.isOpenLdap) {
// openldap supports multiple instances on the same node
return [];
} else {
// samba allows only one instance per node
const disabledNodes = [];

for (const domain of this.domains) {
for (const provider of domain.providers) {
if (provider.id.startsWith("samba")) {
disabledNodes.push(provider.node);
}
}
}
// remove possible duplicates
return [...new Set(disabledNodes)];
}
},
},
watch: {
isShown: function () {
Expand Down
55 changes: 44 additions & 11 deletions core/ui/src/components/domains/CreateDomainModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,25 @@
<div>
{{ $t("domains.choose_node_for_account_provider_installation") }}
</div>
<NodeSelector class="mg-top-xlg" @selectNode="onSelectNode" />
<NsInlineNotification
v-if="clusterNodes.length == disabledNodes.length"
kind="info"
:title="$t('domains.no_node_eligible_for_provider_installation')"
:showCloseButton="false"
/>
<NodeSelector
:disabledNodes="disabledNodes"
@selectNode="onSelectNode"
class="mg-top-xlg"
>
<template v-for="node in clusterNodes">
<template :slot="`node-${node.id}`">
<span v-if="disabledNodes.includes(node.id)" :key="node.id">
{{ $t("domains.provider_already_installed") }}
</span>
</template>
</template>
</NodeSelector>
</template>
<template v-if="step == 'installingProvider'">
<NsInlineNotification
Expand Down Expand Up @@ -489,6 +507,10 @@ export default {
type: Boolean,
default: false,
},
domains: {
type: Array,
default: () => [],
},
},
data() {
return {
Expand Down Expand Up @@ -581,10 +603,7 @@ export default {
computed: {
...mapState(["clusterNodes"]),
nextButtonLabel() {
if (
(this.clusterNodes.length == 1 && this.step == "instance") ||
this.step == "node"
) {
if (this.step == "node") {
return this.$t("domains.install_provider");
} else if (
this.step == "internalConfig" ||
Expand Down Expand Up @@ -645,6 +664,25 @@ export default {
return this.samba.ipAddressOptions;
}
},
disabledNodes() {
if (this.isOpenLdapSelected) {
// openldap supports multiple instances on the same node
return [];
} else {
// samba allows only one instance per node
const disabledNodes = [];

for (const domain of this.domains) {
for (const provider of domain.providers) {
if (provider.id.startsWith("samba")) {
disabledNodes.push(provider.node);
}
}
}
// remove possible duplicates
return [...new Set(disabledNodes)];
}
},
},
watch: {
isShown: function () {
Expand Down Expand Up @@ -694,12 +732,7 @@ export default {
}
break;
case "instance":
if (this.clusterNodes.length > 1) {
this.step = "node";
} else {
this.step = "installingProvider";
this.installProvider();
}
this.step = "node";
break;
case "externalConfig":
this.addExternalDomain();
Expand Down
2 changes: 1 addition & 1 deletion core/ui/src/components/nodes/NodeSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default {
node.selected = false;
}

if (nodes.length == 1) {
if (nodes.length == 1 && !this.disabledNodes.includes(nodes[0].id)) {
nodes[0].selected = true;
}
this.internalNodes = nodes;
Expand Down
55 changes: 4 additions & 51 deletions core/ui/src/views/DomainConfiguration.vue
Original file line number Diff line number Diff line change
Expand Up @@ -341,33 +341,6 @@
:disabled="loading.listUserDomains"
>{{ $t("domain_configuration.add_provider") }}
</NsButton>
<!-- <NsButton ////
v-if="
domain.location == 'external' ||
domain.providers.length < nodes.length
"
kind="secondary"
:icon="Add20"
@click="showAddProviderModal()"
:disabled="loading.listUserDomains"
>{{ $t("domain_configuration.add_provider") }}
</NsButton> -->
<!-- disabled button with tooltip (no nodes available) -->
<!-- <cv-interactive-tooltip
v-else
alignment="center"
direction="right"
class="info"
>
<template slot="trigger">
<NsButton kind="secondary" :icon="Add20" disabled
>{{ $t("domain_configuration.add_provider") }}
</NsButton>
</template>
<template slot="content">
{{ $t('domain_configuration.max_instances_reached') }}
</template>
</cv-interactive-tooltip> -->
</cv-column>
</cv-row>
<cv-row>
Expand Down Expand Up @@ -536,6 +509,7 @@
v-if="domain.location == 'internal'"
:isShown="isShownAddInternalProviderModal"
:domain="domain"
:domains="domains"
:isResumeConfiguration="addProvider.isResumeConfiguration"
:providerId="addProvider.providerId"
@hide="hideAddInternalProviderModal"
Expand Down Expand Up @@ -638,7 +612,6 @@ import AddExternalProviderModal from "@/components/domains/AddExternalProviderMo
import DeleteSambaProviderModal from "@/components/domains/DeleteSambaProviderModal";
import EditPasswordPolicy from "@/components/domains/EditPasswordPolicy";
import Password32 from "@carbon/icons-vue/es/password/32";
import _cloneDeep from "lodash/cloneDeep";
import { mapState } from "vuex";

export default {
Expand Down Expand Up @@ -687,7 +660,6 @@ export default {
domain: {
location: "",
},
internalNodes: [],
isShownLastProviderModal: false,
currentProvider: {
id: "",
Expand All @@ -700,6 +672,7 @@ export default {
},
isShownBindPassword: false,
providerToDelete: null,
domains: [],
loading: {
listUserDomains: true,
ListPasswordPolicy: true,
Expand Down Expand Up @@ -785,6 +758,7 @@ export default {
}
},
listUserDomainsCompleted(taskContext, taskResult) {
this.domains = taskResult.output.domains;
this.domain = taskResult.output.domains.find(
(d) => d.name == this.domainName
);
Expand All @@ -793,8 +767,6 @@ export default {
this.getFqdn();
}
this.loading.listUserDomains = false;
//// fix? maybe available nodes will be retrieved by a dedicated api
this.initNodes();
// scroll to anchor if route URL contains a hash (#)
setTimeout(() => {
this.checkAndScrollToAnchor();
Expand Down Expand Up @@ -986,25 +958,6 @@ export default {
showAddExternalProviderModal() {
this.isShownAddExternalProviderModal = true;
},
initNodes() {
let usedNodes = this.domain.providers.map((provider) => provider.node);
const nodes = _cloneDeep(this.clusterNodes);

for (const node of nodes) {
if (usedNodes.includes(node.id)) {
//// remove mock
// node.unavailable = true; ////
//// do not use unavailable attribute, use NodeSelector disabledNodes property
node.unavailable = false;
node.selected = false;
} else {
//// do not use unavailable attribute, use NodeSelector disabledNodes property
node.unavailable = false;
node.selected = false;
}
}
this.internalNodes = nodes;
},
deleteLdapProvider() {
if (this.domain.location == "internal") {
this.deleteLdapInternalProvider();
Expand Down Expand Up @@ -1287,7 +1240,7 @@ export default {
);
},
getNodeLabel(nodeId) {
const node = this.internalNodes.find((n) => n.id == nodeId);
const node = this.clusterNodes.find((n) => n.id == nodeId);

if (node) {
if (node.ui_name) {
Expand Down
1 change: 1 addition & 0 deletions core/ui/src/views/Domains.vue
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@
:providerId="createDomain.providerId"
:isOpenLdap="createDomain.isOpenLdap"
:isSamba="createDomain.isSamba"
:domains="domains"
@hide="hideCreateDomainModal"
@reloadDomains="listUserDomains"
/>
Expand Down

0 comments on commit c3f943c

Please sign in to comment.