This commit is contained in:
2026-06-25 18:34:45 -05:00
parent da16e5ff56
commit 552b86c323
12 changed files with 439 additions and 125 deletions

View File

@@ -621,6 +621,7 @@
<VCenterConnectionsConfig
:connections="vcenterConnections"
:groups="groups"
:credentials="credentials"
@save="saveVCenterConnection"
@delete="deleteVCenterConnection"
@test="testVCenterConnection"
@@ -1164,25 +1165,25 @@ const settingMetadata = {
section: 'Execution'
},
vcenter_enabled: {
label: 'VMware vCenter',
description: 'Enable VM discovery and import through the VMware vCenter REST API.',
label: 'Legacy vCenter Default',
description: 'Enable the legacy single-vCenter fallback. Saved VMware connections should use Config / VMware with Credential Vault authentication.',
section: 'Integrations'
},
vcenter_base_url: {
label: 'vCenter Base URL',
description: 'Root URL of the vCenter API endpoint used for VM inventory discovery.',
label: 'Legacy vCenter Base URL',
description: 'Fallback vCenter root URL used only when no saved VMware connection is selected.',
placeholder: 'https://vcenter.contoso.local',
section: 'Integrations'
},
vcenter_username: {
label: 'vCenter Username',
description: 'Account used to create vCenter API sessions for host import previews.',
label: 'Legacy vCenter Username',
description: 'Fallback username for the legacy configured default. Prefer Credential Vault-backed saved VMware connections.',
placeholder: 'administrator@vsphere.local',
section: 'Integrations'
},
vcenter_password: {
label: 'vCenter Password',
description: 'Password used only by the backend service when authenticating to vCenter.',
label: 'Legacy vCenter Password',
description: 'Fallback password for the legacy configured default. Prefer Credential Vault-backed saved VMware connections.',
placeholder: 'Stored in app settings or pinned by VCENTER_PASSWORD',
section: 'Integrations',
secret: true

View File

@@ -243,7 +243,7 @@ const activeStatus = computed(() => {
return {
name: connection?.name || 'Selected VMware connection',
typeLabel: connection?.targetType === 'host' ? 'ESXi host' : 'vCenter',
configured: Boolean(connection?.baseUrl && connection?.username),
configured: Boolean(connection?.baseUrl && (connection?.credentialId || connection?.username)),
baseUrl: connection?.baseUrl || ''
};
}

View File

@@ -14,7 +14,7 @@
<div class="intune-config-grid">
<section class="publisher-card">
<strong>Inventory sources</strong>
<p>vCenter entries import VM inventory and power-state checks. Standalone host entries validate direct ESXi connections through the vSphere Web Services API.</p>
<p>vCenter and standalone ESXi entries use Credential Vault entries for VMware API authentication, inventory import, and power-state checks.</p>
<div class="config-stat-row">
<span><b>{{ connections.length }}</b><small>systems</small></span>
<span><b>{{ enabledCount }}</b><small>enabled</small></span>
@@ -28,7 +28,7 @@
<strong>VMware systems</strong>
<div v-for="connection in connections" :key="connection.id" class="check-row">
<b>{{ connection.name }}</b>
<small>{{ connection.baseUrl }} - {{ connectionTypeLabel(connection) }} - {{ connection.apiMode }} - {{ connection.lastTestStatus || 'untested' }}</small>
<small>{{ connection.baseUrl }} - {{ connectionTypeLabel(connection) }} - {{ connection.credentialName || connection.username || 'No vault credential' }} - {{ connection.lastTestStatus || 'untested' }}</small>
<span>
<button class="ghost-button compact" type="button" @click="openModal(connection)">
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i>Edit
@@ -49,7 +49,7 @@
:open="modalOpen"
:title="form.id ? 'Update VMware connection' : 'New VMware connection'"
eyebrow="CONFIG / VMWARE"
description="Store VMware credentials encrypted at rest. vCenter systems can import VM inventory; standalone hosts use the vSphere Web Services API for direct connection validation."
description="Select a Credential Vault username/password entry for VMware API authentication. vCenter systems and standalone ESXi hosts both use the selected vault credential."
wide
@close="modalOpen = false"
>
@@ -63,8 +63,16 @@
</label>
<label><span>Name</span><input v-model="form.name" required :placeholder="form.targetType === 'host' ? 'Rack ESXi host 01' : 'Production vCenter'" /></label>
<label><span>Base URL</span><input v-model="form.baseUrl" required :placeholder="baseUrlPlaceholder" /></label>
<label><span>Username</span><input v-model="form.username" required :placeholder="form.targetType === 'host' ? 'root or delegated ESXi account' : 'administrator@vsphere.local'" /></label>
<label><span>{{ form.id ? 'Replace password' : 'Password' }}</span><input v-model="form.password" :required="!form.id" type="password" placeholder="Stored encrypted after save" /></label>
<label class="full">
<span>Credential Vault entry</span>
<select v-model="form.credentialId" required>
<option value="" disabled>Choose VMware API credential</option>
<option v-for="credential in vmwareCredentials" :key="credential.id" :value="credential.id">
{{ credential.name }}{{ credential.username ? ` - ${credential.username}` : '' }}
</option>
</select>
<small>Use a username/password credential. Create or update secrets in Credential Vault.</small>
</label>
<label>
<span>API mode</span>
<select v-model="form.apiMode" :disabled="form.targetType === 'host'">
@@ -98,7 +106,8 @@ import BaseModal from '../ui/BaseModal.vue';
const props = defineProps({
connections: { type: Array, default: () => [] },
groups: { type: Array, default: () => [] }
groups: { type: Array, default: () => [] },
credentials: { type: Array, default: () => [] }
});
const emit = defineEmits(['save', 'delete', 'test']);
@@ -109,6 +118,7 @@ const enabledCount = computed(() => props.connections.filter((connection) => con
const vcenterCount = computed(() => props.connections.filter((connection) => connection.targetType !== 'host').length);
const standaloneCount = computed(() => props.connections.filter((connection) => connection.targetType === 'host').length);
const testedCount = computed(() => props.connections.filter((connection) => connection.lastTestStatus).length);
const vmwareCredentials = computed(() => props.credentials.filter((credential) => credential.kind === 'username_password'));
const baseUrlPlaceholder = computed(() => form.targetType === 'host' ? 'https://esxi01.contoso.local' : 'https://vcenter.contoso.local');
const enabledHelpText = computed(() => form.targetType === 'host'
? 'Allow this standalone host connection to be tested and used for direct VMware host workflows.'
@@ -128,8 +138,7 @@ function defaultForm() {
name: '',
targetType: 'vcenter',
baseUrl: '',
username: '',
password: '',
credentialId: '',
apiMode: 'auto',
requestTimeoutMs: 20000,
allowUntrustedTls: false,
@@ -143,7 +152,7 @@ function openModal(connection = null) {
Object.assign(form, defaultForm(), connection || {});
form.targetType = connection?.targetType || 'vcenter';
form.apiMode = form.targetType === 'host' ? 'web-services' : (connection?.apiMode || 'auto');
form.password = '';
form.credentialId = connection?.credentialId || '';
form.groupId = connection?.groupId || '';
modalOpen.value = true;
}