UNPKG

@kinvolk/headlamp-plugin

Version:

The needed infrastructure for building Headlamp plugins.

145 lines (144 loc) 6.15 kB
/* * Copyright 2025 The Kubernetes Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Prepares the information needed to run a plugin with the `runPlugin` function. * * This function gathers the necessary details such as source code, package name, * version, and permissions, and returns them in a structured format that can be * used to execute the plugin with the `runPlugin` function. * * This is a separate step to reduce the amount of information available to the `runPlugin` function. * * @param source source code of plugin * @param pluginPath path to plugin * @param packageName name of package * @param packageVersion version of package * @param permissionSecrets permission secrets are keyed by permission name, valued by secret * @param handleError call back when an execution error occurs in the plugin * @param getAllowedPermissions call back which returns only allowed permission secrets for plugin * @param getArgValues call back which returns the argument names and values for the plugin * @param privateFunction is a non global private copy of Function */ export function getInfoForRunningPlugins({ source, pluginPath, packageName, packageVersion, permissionSecrets, handleError, getAllowedPermissions, getArgValues, PrivateFunction, internalRunPlugin, consoleError, }) { if (!pluginPath || !packageName || !packageVersion) { consoleError(`Either pluginPath, packageName or packageVersion is missing for ${pluginPath}`); return; } const sourceMapPathForDebugging = `\n//# sourceURL=//${pluginPath}/dist/main.js`; const allowedPermissions = getAllowedPermissions(packageName, pluginPath, permissionSecrets); const argsValues = getArgValues(packageName, pluginPath, allowedPermissions); const args = argsValues[0]; const values = argsValues[1]; // Using an array here because it's a bit safer than an object for this use. return [ source + sourceMapPathForDebugging, packageName, packageVersion, handleError, PrivateFunction, args, values, internalRunPlugin, consoleError, ]; } /** * Runs a plugin by executing the source code in the global scope. * * This provides a way to pass private variables to individual plugins. * * @param source source code of plugin * @param packageName name of package * @param packageVersion version of package * @param handleError call back when an execution error occurs in the plugin * @param PrivateFunction is a non global private copy of Function * @param args The argument names to be given to the plugin * @param values The values for the arguments to be given to the plugin * * @see getInfoForRunningPlugins for more details */ export function runPlugin(source, packageName, packageVersion, handleError, PrivateFunction, args, values) { // We use PrivateFunction here instead of global Function so people can't // override Function and snoop on it. const executePlugin = new PrivateFunction(...args, source); try { // This executes in the global scope, // so the plugin can't access variables in this scope. // Meaning, it can NOT access "permissionSecrets". // Each plugin gets its own "pluginPermissionSecrets" which contains only the secrets // that it is allowed to access. executePlugin(...values); } catch (e) { handleError(e, packageName, packageVersion); } } /** * Identifies which packages this is, taking into account prereleases, and development mode. * * @param pluginPath is like "plugins/headlamp-pod-counter" * @param pluginName is like "@headlamp-k8s/minikube" * @param isDevelopmentMode * @returns the packages with { '@headlamp-k8s/minikube': true } * * @example * > identifyPackages('plugins/headlamp_minikube', '@headlamp-k8s/minikube', false) * { '@headlamp-k8s/minikube': true } */ export function identifyPackages(pluginPath, pluginName, isDevelopmentMode) { // Normalize path for Windows compatibility const pluginPathNormalized = pluginPath .replace(/plugins[\\/]/, 'plugins/') .replace(/static-plugins[\\/]/, 'static-plugins/') .replace(/user-plugins[\\/]/, 'user-plugins/'); // For artifacthub installed packages, the package name is the folder name. const pluginPaths = { '@headlamp-k8s/minikube': [ 'plugins/headlamp_minikube', 'user-plugins/headlamp_minikube', 'static-plugins/headlamp_minikube', 'plugins/headlamp_minikubeprerelease', 'user-plugins/headlamp_minikubeprerelease', 'static-plugins/headlamp_minikubeprerelease', ], }; if (isDevelopmentMode) { pluginPaths['@headlamp-k8s/minikube'][pluginPaths['@headlamp-k8s/minikube'].length] = 'plugins/minikube'; } const pluginPackageNames = { '@headlamp-k8s/minikube': ['@headlamp-k8s/minikube', '@headlamp-k8s/minikubeprerelease'], }; const isPackage = {}; for (const key in pluginPaths) { let foundPath = false; for (let i = 0; i < pluginPaths[key].length; i++) { if (pluginPaths[key][i] === pluginPathNormalized) { foundPath = true; break; } } let foundName = false; for (let i = 0; i < pluginPackageNames[key].length; i++) { if (pluginPackageNames[key][i] === pluginName) { foundName = true; break; } } isPackage[key] = foundPath && foundName; } return isPackage; }