UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

180 lines (178 loc) 9.32 kB
import { of, zip } from 'rxjs'; import { map, mergeMap } from 'rxjs/operators'; import { PowerShell } from '../../data/powershell'; import { PowerShellScripts } from '../../generated/powershell-scripts'; import { ServerInventoryCache } from '../server-inventory/server-inventory-cache'; import { SharedCache } from '../shared-cache'; import { ClusterInventory } from './cluster-inventory'; import { ClusterNodeInventory, ClusterNodeState } from './cluster-node-inventory'; /** * Cluster Inventory cache class. */ export class ClusterInventoryCache extends SharedCache { appContext; static uniqueId = '@msft-sme/shell:clusterInventory'; static uniqueVersion = 1; // increment this if you make breaking changes serverInventoryCache; /** * Initializes a new instance of the ClusterInventoryCache class. * * @param appContext the app context. * @param options the option of shared cache. */ constructor(appContext, options) { super(ClusterInventoryCache.uniqueId, ClusterInventoryCache.uniqueVersion, (params) => this.dataInstanceId(params), (instance) => this.dataSerialize(instance), (serialized) => this.dataDeserialize(serialized), (params) => this.dataQuery(params), options); this.appContext = appContext; this.serverInventoryCache = new ServerInventoryCache(appContext); } /** * Defines how to identify the cache entry by params. * * @param params the server inventory query params. * @return the id string. */ dataInstanceId(params) { return params.name; } /** * Defines how to deserialize the class object from serialized data. * * @param serialized the serialized string; */ dataDeserialize(serialized) { const inventory = JSON.parse(serialized); return new ClusterInventory(inventory.clusterName, inventory); } /** * Defines how to serialize the class object to serialized data. * * @param instance the class instance. */ dataSerialize(instance) { // automatically stripped out class related data. return JSON.stringify(instance); } /** * Defines how to collect the cluster inventory data. * * @param params the server inventory query params. * @return the Observable of ClusterInventory data. */ dataQuery(params) { // options object will be updated at the http layer, so it makes an each copy before passing. const options = { ...params.requestOptions }; const clusterPsSession = this.appContext.powerShell.createSession(params.name, null, options); const clusterNodePsSession = this.appContext.powerShell.createSession(params.name, null, options); return zip(this.appContext.powerShell.run(clusterPsSession, PowerShell.createCommand(PowerShellScripts.Get_ClusterInventory)), this.appContext.powerShell.run(clusterNodePsSession, PowerShell.createCommand(PowerShellScripts.Get_ClusterNodes))) .pipe(map(([cluster, nodes]) => { const inventory = new ClusterInventory(params.name); if (!cluster || !cluster.results || cluster.results.length === 0) { return inventory; } if (!nodes || !nodes.results || nodes.results.length === 0) { return inventory; } const nodesResult = nodes.results[0]; const clusterResult = cluster.results[0]; const nodesResultLower = {}; // make node name and fqdn lower casing. inventory.isClusterCmdletAvailable = clusterResult.isClusterCmdletAvailable; clusterResult.fqdn = clusterResult.fqdn?.toLowerCase(); inventory.fqdn = clusterResult.fqdn; inventory.currentClusterNode = clusterResult.currentClusterNode.toLowerCase(); inventory.nodeNames = []; for (const node in nodesResult) { if (node && nodesResult[node] && nodesResult[node].name) { nodesResult[node].name = nodesResult[node].name.toLowerCase(); nodesResult[node].fullyQualifiedDomainName = nodesResult[node].fullyQualifiedDomainName.toLowerCase(); inventory.nodeNames.push(nodesResult[node].name); const nodeLower = node.toLowerCase(); nodesResultLower[nodeLower] = nodesResult[node]; } } inventory.isS2dEnabled = clusterResult.isS2DEnabled; inventory.isTsdbEnabled = clusterResult.isTsdbEnabled; inventory.isBritannicaEnabled = clusterResult.isBritannicaEnabled; inventory.isBritannicaVirtualMachineEnabled = clusterResult.isBritannicaVirtualMachineEnabled; inventory.isBritannicaVirtualSwitchEnabled = clusterResult.isBritannicaVirtualSwitchEnabled; inventory.isClusterHealthCmdletAvailable = clusterResult.isClusterHealthCmdletAvailable; inventory.isHyperVPowershellInstalled = false; inventory.isHyperVRoleInstalled = false; inventory.isManagementToolsAvailable = false; inventory.nodeMap = nodesResultLower; return inventory; }), mergeMap(inventory => this.queryClusterNodeInventories(inventory, params))); } /** * Defines how to collect the cluster node-server inventory data. * @param clusterInventory the initial cluster inventory query params. * @param params the parameters for cluster inventory query. * @return Observable<ClusterInventory> the Observable of ClusterInventory data. */ queryClusterNodeInventories(clusterInventory, params) { if (!clusterInventory.nodeNames || clusterInventory.nodeNames.length === 0) { return of(clusterInventory); } // Can only get server inventory data from live nodes const nodeMap = clusterInventory.nodeMap; const liveNodeNames = []; for (const key in nodeMap) { if (nodeMap[key].state === ClusterNodeState.Up || nodeMap[key].state === ClusterNodeState.Paused) { liveNodeNames.push(nodeMap[key].fullyQualifiedDomainName); } } const authToken = this.appContext.authorizationManager.getSavedNodeToken(params.name); let options = {}; if (params.requestOptions) { options = { ...params.requestOptions }; if (options.authToken == null && authToken) { // override auth token if not there. options.authToken = authToken; } } else if (authToken) { options.authToken = authToken; } const errorMessages = []; const batchSession = this.appContext.powerShell.createBatchSession(liveNodeNames, null, options); return this.appContext.powerShell.runBatchSingleCommand(batchSession, PowerShell.createCommand(PowerShellScripts.Get_ServerInventory)) .pipe(map((responseItems) => { for (let index = 0; index < responseItems.length; index++) { const response = responseItems[index]; if (response.error || response.errors) { const message = (response.error && response.error.message) || (response.errors && response.errors[0] && response.errors[0].message); errorMessages.push(message); continue; } const currentServer = liveNodeNames[index]; const serverNameParts = currentServer.split('.'); const serverName = serverNameParts.length > 1 ? serverNameParts[0] : currentServer; const data = response.properties; const serverInventory = ServerInventoryCache.createServerInventoryData(serverName, data); this.serverInventoryCache.save({ name: serverName }, serverInventory); const inventoryServerName = clusterInventory.nodeMap[clusterInventory.currentClusterNode].name; if (serverName === inventoryServerName) { clusterInventory.isHyperVPowershellInstalled = serverInventory.isHyperVPowershellInstalled; clusterInventory.isHyperVRoleInstalled = serverInventory.isHyperVRoleInstalled; clusterInventory.isManagementToolsAvailable = serverInventory.isManagementToolsAvailable; } // combine cluster node inventory and server inventory const clusterNodeInventory = new ClusterNodeInventory(serverName); const clusterServerInventory = clusterInventory.nodeMap[serverName]; Object.assign(clusterNodeInventory, serverInventory); for (const property in clusterServerInventory) { if (property) { clusterNodeInventory[property] = clusterServerInventory[property]; } } clusterInventory.nodeMap[serverName] = clusterNodeInventory; } if (errorMessages.length > 0) { clusterInventory.clusterErrors = errorMessages; } return clusterInventory; })); } } //# sourceMappingURL=cluster-inventory-cache.js.map