diff --git a/source/ext/spellchecking/wordlists/opennebula.txt b/source/ext/spellchecking/wordlists/opennebula.txt index fdeb995f86..ce8434c9a4 100644 --- a/source/ext/spellchecking/wordlists/opennebula.txt +++ b/source/ext/spellchecking/wordlists/opennebula.txt @@ -153,6 +153,7 @@ Unmanaged Unregister Untagged Uplink +Utils VID VMs VMware @@ -165,6 +166,7 @@ Virtualized Vms Vnet Vrouter +Webpack Webserver XPath Xeon @@ -298,8 +300,8 @@ deldatastore delgroup delhost delrule -delvnet delserver +delvnet desc detachdisk detachnic @@ -652,10 +654,10 @@ seSparse secgroup secgrouppool securetty +server-del serveradmin serverless serveruser -server-del sftp sg sgID @@ -820,6 +822,7 @@ vrouter vrouterpool vxlan webhook +webpack webrick webserver websockets diff --git a/source/images/fireedge_fallback_editor.png b/source/images/fireedge_fallback_editor.png new file mode 100644 index 0000000000..61b7fa4878 Binary files /dev/null and b/source/images/fireedge_fallback_editor.png differ diff --git a/source/images/users_and_groups_tab.png b/source/images/users_and_groups_tab.png new file mode 100644 index 0000000000..e47d2fd337 Binary files /dev/null and b/source/images/users_and_groups_tab.png differ diff --git a/source/integration_and_development/references/sunstone_dev.rst b/source/integration_and_development/references/sunstone_dev.rst index d44e3d480b..e8b40f52e6 100644 --- a/source/integration_and_development/references/sunstone_dev.rst +++ b/source/integration_and_development/references/sunstone_dev.rst @@ -4,9 +4,8 @@ Sunstone Development ================================================================================ -OpenNebula FireEdge server provides a **next-generation web-management interface**. It is able to deliver several applications accessible through the following URLs: +OpenNebula FireEdge server provides a **next-generation web-management interface**. -- Provision GUI: ``:2616/fireedge/provision>`` - Sunstone GUI: ``:2616/fireedge/sunstone>`` (automatically redirected from ``:2616/``) This second Sunstone incarnation is written in `React `__ / `Redux `__ and `Material-UI `__ is used for the styles and layout of the web. @@ -21,10 +20,682 @@ Then move to FireEdge directory (``src/fireedge``) and run: $ npm i # Install dependencies from package.json $ npm run # List the available scripts - $ npm run dev # Start the development server. By default on http://localhost:2616/fireedge + $ npm run build # Build all the modules. + $ npm run start # Start the server, by default accessible on http://localhost:2616/fireedge You can read more about this in the :ref:`FireEdge configuration guide `. +Architecture +================================================================================ + +In our latest generation of FireEdge Sunstone, we have done a architectural revamp, moving from our previously Monolithic architecture towards a more modern and streamlined Micro-Frontend like architecture. This new architecture is based on the latest Module Federation implementation in `Webpack `_. Which allows us to dynamically, and remotely, load different modules in our baseline Sunstone client. + +.. _base_modules: + +The Sunstone client has been split up into **8** different base modules: + + * Components. + * Constants. + * Containers. + * Features. + * Hooks. + * Models. + * Providers. + * Utils. + +These modules have been separated in such a way that no hard links exist between them. Any internal cross-module dependencies are handled at runtime, by the module federation through it's shared dependency scope. This ensures modules can be rebuilt and served separately from each other. + +.. note:: By default, when a new version is released, all modules are packaged and shipped with the client, and served from the FireEdge server. + + +.. _remotes_config: + +Remotes Configuration +================================================================================ + +The ``remotes-config.json`` file, typically located at ``/etc/one/fireedge/sunstone/remotes-config.json``, dictates where different modules are loaded from. At a minimum, the eight :ref:`base modules ` must be defined in this file, in order for the client to load properly. + +The configuration file is structured according to the following schema: + +.. code-block:: json + + { + "": { + "name": "", + "entry": "" + }, + } + +Where: + * ```` : A unique identifier for the module. Typically matches ``name`` but serves as the configuration key. + * ``name`` : The runtime namespace exposed by the module. Must match the ``name`` configured in the remote module's Webpack configuration file. + * ``entry`` : The URL to the module's ``remoteEntry.js`` file. + +Notes: +------ +- Each module's ``entry`` must point to a valid and accessible ``remoteEntry.js`` file. +- The ``name`` property must match the runtime namespace as defined in the remote module's Webpack configuration. +- The ```` and ``name`` can be identical but are defined separately to allow flexibility in naming conventions. + +.. tip:: + The ``__HOST__`` flag can be used to simplify setups, as this resolves to the current navigator URL in the client. This should be used most of the time when the remote modules are being served directly from the FireEdge server. + +This example shows the default configuration of the different modules, when they are being loaded locally from the FireEdge server. + +.. code-block:: json + + { + "UtilsModule": { + "name": "UtilsModule", + "entry": "__HOST__/fireedge/modules/UtilsModule/remoteEntry.js" + }, + "ConstantsModule": { + "name": "ConstantsModule", + "entry": "__HOST__/fireedge/modules/ConstantsModule/remoteEntry.js" + }, + "ContainersModule": { + "name": "ContainersModule", + "entry": "__HOST__/fireedge/modules/ContainersModule/remoteEntry.js" + }, + "ComponentsModule": { + "name": "ComponentsModule", + "entry": "__HOST__/fireedge/modules/ComponentsModule/remoteEntry.js" + }, + "FeaturesModule": { + "name": "FeaturesModule", + "entry": "__HOST__/fireedge/modules/FeaturesModule/remoteEntry.js" + }, + "ProvidersModule": { + "name": "ProvidersModule", + "entry": "__HOST__/fireedge/modules/ProvidersModule/remoteEntry.js" + }, + "ModelsModule": { + "name": "ModelsModule", + "entry": "__HOST__/fireedge/modules/ModelsModule/remoteEntry.js" + }, + "HooksModule": { + "name": "HooksModule", + "entry": "__HOST__/fireedge/modules/HooksModule/remoteEntry.js" + } + } + +.. hint:: Loading modules over HTTPS is fully supported and requires no extra setting up in the client. + + +A module fails to load +-------------------------------------------------------------------------------- + +In the case that a module fails to load, either due to a failed network request or due to a error in the code itself, the `fallback editor` will be employed. The client checks all modules when loading to make sure that they are properly initialized, in order to try and prevent and narrow down any fatal problems as early on as possible. The fallback editor allows the user to try and repair any misconfigured remotes, directly in the browser. + +The server passes the ``remotes-config.json`` file to the client through the `Window Interface `__, accessible through ``window.__REMOTES_MODULE_CONFIG__`` from the browser console. This configuration gets potentially modified by the `fallback editor` and cached using the browsers `localStorage API `__. This cache is implemented in order for the client to be able to use a temporary configuration that persists across reloads, in order to mitigate potential lockouts from the user interface. + +|image_fallback_editor| + +Inside the fallback editor, you will have access to a simple interface, consisting of a text area for editing the configured remotes (changes do not affect any file on-disk), and three different buttons. + +Where: + * ``Reset`` : Resets the entire configuration to the minimal eight :ref:`base modules `. + * ``Clear fallback configuration`` : Clears the fallback flag, discarding any modifications made to the ``remotes-config.json`` file loaded from the server & attempts to re-use it. + * ``Continue`` : Attempts to continue loading the currently defined configuration. + + +Tab Manifest +================================================================================ + +The ``tab-manifest.json`` file, typically located at ``/etc/one/fireedge/sunstone/tab-manifest.json``, controls the loading of components and is the key to dynamic tab management. This file allows you to dynamically specify new endpoints and how different modules are loaded at those endpoints. + +The configuration file is structured according to the following schema: + +.. code-block:: json + + { + "title": "", + "path": "", + "sidebar": "", + "icon": "", + "moduleId": "", + "Component": "" + } + +Where: + * ``title``: The display name of the tab as shown in the UI. + * ``path``: The URL path that maps to this tab. It must be unique across all tabs. + * ``sidebar``: A boolean (`true` or `false`) Indicates whether the tab should appear in the sidebar navigation. + * ``icon``: The name of the icon to represent the tab visually. Must correspond to a valid icon identifier from the `iconoir-react library `__. + * ``moduleId``: The identifier for the remote module. It must match the `name` field in the corresponding module's entry in the ``remotes-config.json``. + * ``Component``: The exported name of the component that renders the tab's content. + +.. note:: The client searches for the ``Component`` from the base of the ```` and does not support nested imports. All modules should expose their exports through a global barrel file, see :ref:`Module webpack configuration ` for more details. + + +Adding a new tab +-------------------------------------------------------------------------------- + +In order to develop a new tab, you need to make sure it has the correct webpack configuration & has been added to the ``tab-manifest.json`` & ``remotes-config.json`` files. In this example we will use the `OpenNebula ONE repo `__ to create a new module and add it to the Sunstone client. + + +1. Begin by cloning the `one repo `__. + + .. prompt:: bash + + git clone git@github.com:OpenNebula/one.git + # Cd into the fireedge directory + cd ./one/src/fireedge + +2. Build the :ref:`base modules ` & start the fireedge server + + .. prompt:: bash $ auto + + $ npm i # Install dependencies from package.json + $ npm run # List the available scripts + $ npm run build # Build all the modules. + $ npm run start # Start the server, by default accessible on http://localhost:2616/fireedge + + Now lets create a new module called ``CustomContainers``, based off the original ``ContainersModule``. + +3. We will begin by creating a new ``src/modules/customContainers`` folder + + .. prompt:: bash + + mkdir -p src/modules/customContainers + +4. Then we'll copy the ``/Users`` directory & webpack configuration file from the original ``ContainersModule`` + + .. prompt:: bash $ auto + + # Copying the Users directory + cp -r src/modules/containers/Users src/modoules/customContainers + + # Copying containers webpack config for reference + cp src/modules/containers/webpack.config.prod.containers.js src/modules/customContainers/webpack.config.prod.customcontainers.js + + # We'll also create a index.js file which will expose our new component + touch src/modules/customContainers/index.js + +5. Now we need to modify the ``webpack.config.prod.customcontainers.js`` file + + .. code-block:: javascript + + // We will update the module name at the top to `CustomContainers` + const moduleName = 'ContainersModule' + + // Make sure your module can import the shared dependency script! + const sharedDeps = require('../sharedDeps') + + .. note:: + We can now save this file as this is really the only modification we need to make, assuming we don't want to add any new dependencies to the shared context scope, which is defined in ``src/modules/sharedDeps.js`` if you want to have a look. + + The ``sharedDeps.js`` file imports the ``package.json`` file in order to parse dependency versions, but these can be overwritten and modified as you see fit. + + .. code-block:: javascript + + const deps = require('../../package.json').dependencies + + const sharedDeps = ({ eager = false } = {}) => ({ + react: { + singleton: true, + eager, + requiredVersion: deps.react, + }, + // Add other dependencies here as needed + }) + + module.exports = sharedDeps + +6. Moving onto the actual code now, we'll move into the new ``customContainers`` directory and modify the ``Users.js`` file. + + For this example, we'll modify the normal Users component to also display groups in a column like layout. + + .. code-block:: javascript + + import { Chip, Stack, Typography, Grid } from '@mui/material' // Adding the Grid import + + import { + Tr, + MultipleTags, + ResourcesBackButton, + GroupsTable, // Adding the GroupsTable import + UsersTable, + UserTabs, + SubmitButton, + TranslateProvider, + } from '@ComponentsModule' + + + .. note:: Notice how we import from the ``@ComponentsModule`` instead of using a relative path to the ``src/modules/components`` directory. This is because the import goes through the module federation and is resolved dynamically at runtime, as opposed to being bundled within our new module directly. + +.. important:: Cross-module imports should *NEVER* be done relative to one another, only inside subdirectories of the module itself should you use relative import paths like ``import ... from @modules/``. See :ref:`importing from other modules ` for more information. + +7. Now lets rename our component to "UsersAndGroups" and modify the code so that we return a 2 column grid with both our tables inside + + .. code-block:: jsx + + export function UsersAndGroups() { + const [selectedRows, setSelectedRows] = useState(() => []) + const actions = UsersTable.Actions() + const { zone } = useGeneral() + + return ( + + ( + + + + + + + + + + )} + simpleGroupsTags={(props) => ( + + )} + info={(props) => { + const propsInfo = { + user: props?.selectedRows?.[0]?.original, + selectedRows: props?.selectedRows, + } + props?.gotoPage && (propsInfo.gotoPage = props.gotoPage) + props?.unselect && (propsInfo.unselect = props.unselect) + + return + }} + /> + + ) + } + +8. Now that we have saved our modified ``Users.js`` file, we need to make sure we are exporting it properly inside our ``index.js`` file (``src/modules/customContainers/index.js``) + + .. code-block:: javascript + + export * from '@modules/customContainers/Users' + + Also update the exports inside the ``src/modules/customContainers/Users/index.js`` file, as it will point to the wrong directory otherwise + + .. code-block:: javascript + + export * from '@modules/customContainers/Users/Users' + + .. note:: Here the ``@modules`` name is an alias we use in our webpack configuration, which gets resolved to the ``src/modules`` directory when building. You can examine this more closely inside the ``webpack.config.prod.customcontainer.js`` file. In this case, exporting relative to our parent directory is fine as we are not doing any cross-module referencing. See the :ref:`module webpack configuration ` section for more information. + +9. Time to build our module (for convenience sake, we will save the build command inside our ``package.json`` file) + + .. code-block:: javascript + + "scripts": { + "build:ctm": "rimraf dist/modules/ContainersModule && BUILD_TARGET=remote webpack --config ./src/modules/containers/webpack.config.prod.containers.js", + + // Adding it under the alias "build:ccm" + "build:ccm": "rimraf dist/modules/CustomContainersModule && BUILD_TARGET=remote webpack --config ./src/modules/customContainers/webpack.config.prod.customContainers.js", + // More module build commands + } + + Running the build command + + .. prompt:: bash + + npm run build:ccm # Building our customContainersModule + > FireEdge@1.0.0 build:ccm + > rimraf dist/modules/CustomContainersModule && BUILD_TARGET=remote webpack --config ./src/modules/customContainers/webpack.config.prod.customContainers.js + + assets by info 717 KiB [immutable] + assets by chunk 647 KiB (id hint: vendors) + asset 659aeeaf6d97dbdbd377.734.js 419 KiB [emitted] [immutable] [minimized] [big] (id hint: vendors) 1 related asset + asset d29140b066ef871bf666.935.js 121 KiB [emitted] [immutable] [minimized] (id hint: vendors) 1 related asset + asset 14fdb556980b10379dbe.521.js 55.1 KiB [emitted] [immutable] [minimized] (id hint: vendors) 1 related asset + asset 4506de3a3b041a88614a.977.js 15.3 KiB [emitted] [immutable] [minimized] (id hint: vendors) 1 related asset + asset 8e4788e4aa133cc51773.350.js 13.3 KiB [emitted] [immutable] [minimized] (id hint: vendors) 1 related asset + asset d81938165469db579b06.586.js 12.9 KiB [emitted] [immutable] [minimized] (id hint: vendors) 1 related asset + asset 932b89d7c980f063ba5f.657.js 10.3 KiB [emitted] [immutable] [minimized] (id hint: vendors) 1 related asset + 14 assets + asset main.bundle.js 20.4 KiB [emitted] [minimized] (name: main) 1 related asset + asset remoteEntry.js 11.3 KiB [emitted] [minimized] (name: CustomContainersModule) 1 related asset + orphan modules 1.69 MiB (javascript) 42 bytes (consume-shared) [orphan] 801 modules + runtime modules 48.3 KiB 26 modules + built modules 1.85 MiB (javascript) 564 bytes (share-init) 504 bytes (consume-shared) 18 bytes (remote) [built] + javascript modules 1.85 MiB 49 modules + provide-module modules 546 bytes + modules by path provide shared module (default) prop-types@15.8.1 = ./node_modules/@mui/ 126 bytes 3 modules + modules by path provide shared module (default) @emotion/ 84 bytes 2 modules + consume-shared-module modules 504 bytes + modules by path consume shared module (default) prop-types@=15.7.2 (singleton) (fallback: ./node_modules/ 126 bytes 3 modules + modules by path consume shared module (default) @emotion/ 84 bytes 2 modules + remote-module modules 18 bytes (remote) 18 bytes (share-init) + remote @FeaturesModule 6 bytes (remote) 6 bytes (share-init) [built] [code generated] + remote @ComponentsModule 6 bytes (remote) 6 bytes (share-init) [built] [code generated] + remote @ConstantsModule 6 bytes (remote) 6 bytes (share-init) [built] [code generated] + + WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB). + This can impact web performance. + Assets: + 659aeeaf6d97dbdbd377.734.js (419 KiB) + + webpack 5.64.4 compiled with 1 warning in 2911 ms + +10. Now we need to copy our new module to the ``/usr/lib/one/fireedge/dist/modules`` directory, as we will be serving it locally + + + .. prompt:: bash + + cp -r dist/modules/customContainers /usr/lib/one/fireedge/dist/modules + + This ensures the fireedge server has access to and can serve the module for the client + +11. Now we need to add our module to the ``remotes-config.json`` file + + .. code-block:: json + + { + "ContainersModule": { + "name": "ContainersModule", + "entry": "__HOST__/fireedge/modules/ContainersModule/remoteEntry.js" + }, + "CustomContainersModule": { + "name": "CustomContainersModule", + "entry": "__HOST__/fireedge/modules/CustomContainersModule/remoteEntry.js" + } + } + + Now the client will fetch and load the ``CustomContainersModule`` + +12. Then we need to update out ``tab-manifest.json`` file with our new ``UsersAndGroups`` component + + .. code-block:: json + + { + "title": "System", + "icon": "Home", + "routes": [ + { + "title": "Create User", + "path": "/user/create", + "Component": "CreateUser" + }, + { + "title": "Users and Groups", + "path": "/usersgroups", + "sidebar": true, + "icon": "User", + "moduleId": "CustomContainersModule", // We explicitly define which module to load the component from + "Component": "UsersAndGroups" + }, + // Other tabs and definitions + ] + } + + + .. important:: Make sure to add the ``moduleId`` pointing to the "CustomContainersModule", as otherwise the client will attempt loading the Component from the default ``ContainersModule`` + +13. Finally we need to add a new :ref:`view configuration `, allowing us to access the `/usersgroups` endpoint + + We will do this for the oneadmin user only + + .. prompt:: bash + + cp /etc/one/fireedge/sunstone/admin/user-tab.yaml /etc/one/fireedge/sunstone/admin/usersgroups-tab.yaml + + + And then we update the resource name inside the new ``usersandgroups-tab.yaml`` view file to match the path of our component + + .. code-block:: yaml + + resource_name: "USERSGROUPS" + + +Now open up your Sunstone web UI (should be reachable at ``http://localhost:2616/fireedge``) and you should have a new tab under the "System" category, named "Users and Groups", which displays both the users and groups table next to each other! + +|users_and_groups_tab| + +Note that all of this was done with the FireEdge Sunstone server up and running in production mode, as the new modularized architecture does not require us to rebuild the client nor the server in order to bring in new changes. + +.. _module_webpack_configuration: + +Module Webpack Configuration +================================================================================ + +When defining a new module, you need to make sure that it has a correctly defined webpack configuration file. This configuration file can be tweaked as you see fit, but should include a few key options in order to be compatible with the Sunstone client. + +.. _default_module_webpack: + +This example shows the default webpack configuration file for a module. + +.. code-block:: javascript + + const moduleName = '' // This is how the module will be referenced + const path = require('path') + const { ModuleFederationPlugin } = require('webpack').container + const sharedDeps = require('../sharedDeps') // Dependencies shared between modules + const TerserPlugin = require('terser-webpack-plugin') + const ExternalRemotesPlugin = require('external-remotes-plugin') + const ONE_LOCATION = process.env.ONE_LOCATION + const ETC_LOCATION = ONE_LOCATION ? `${ONE_LOCATION}/etc` : '/etc' + + // The path to the remotes-config.json file, necessary in order to resolve cross-module dependencies when building. + const remotesConfigPath = + process.env.NODE_ENV === 'production' + ? `${ETC_LOCATION}/one/fireedge/sunstone/remotes-config.json` + : path.resolve( + __dirname, + '..', + '..', + '..', + 'etc', + 'sunstone', + 'remotes-config.json' + ) + + const remotesConfig = require(remotesConfigPath) + + const configuredRemotes = Object.entries(remotesConfig) + .filter(([_, { name }]) => name !== moduleName) + .reduce((acc, [module, { name }]) => { + acc[ + `@${module}` + ] = `${name}@[window.__REMOTES_MODULE_CONFIG__.${module}.entry]` + + return acc + }, {}) + + module.exports = { + mode: 'production', + entry: path.resolve(__dirname, 'index.js'), + output: { + path: path.resolve(__dirname, '../../../', 'dist', 'modules', moduleName), + filename: '[name].bundle.js', + chunkFilename: '[contenthash].[id].js', + uniqueName: moduleName, + publicPath: 'auto', + }, + plugins: [ + new ModuleFederationPlugin({ + name: moduleName, + filename: 'remoteEntry.js', + exposes: { + '.': path.resolve(__dirname, 'index.js'), + }, + remotes: configuredRemotes, + shared: sharedDeps({ eager: false }), + }), + new ExternalRemotesPlugin(), + ], + + optimization: { + minimizer: [new TerserPlugin({ extractComments: false })], + moduleIds: 'deterministic', + chunkIds: 'deterministic', + }, + resolve: { + alias: { + '@modules': path.resolve(__dirname, '../'), + }, + }, + devtool: 'source-map', + stats: { + errorDetails: true, + warnings: true, + }, + experiments: { + topLevelAwait: true, + }, + module: { + rules: [ + { + test: /\.js$/, + use: 'babel-loader', + include: path.resolve(__dirname, '../../'), + }, + { + test: /\.(png|jpe?g|gif)$/i, + use: [ + { + loader: 'file-loader', + options: { + name: '[path][name].[ext]', + outputPath: 'assets/images/', + }, + }, + ], + }, + ], + }, + } + +When creating a new module, you can use :ref:`this ` template as a base. Just make sure you update the ```` to match the name of your module. + +.. _resolving_remote_modules: + +Resolving other modules +-------------------------------------------------------------------------------- + +Make sure you have added all your modules to the correct :ref:`remotes-config.json ` file, as this file will be imported during builds to help resolve remote module imports. + +.. code-block:: javascript + + // The path to the remotes-config.json file, necessary in order to resolve cross-module dependencies when building. + const remotesConfigPath = + process.env.NODE_ENV === 'production' + ? `${ETC_LOCATION}/one/fireedge/sunstone/remotes-config.json` + : path.resolve( + __dirname, + '..', + '..', + '..', + 'etc', + 'sunstone', + 'remotes-config.json' + ) + + const remotesConfig = require(remotesConfigPath) + + const configuredRemotes = Object.entries(remotesConfig) + .filter(([_, { name }]) => name !== moduleName) + .reduce((acc, [module, { name }]) => { + acc[ + `@${module}` + ] = `${name}@[window.__REMOTES_MODULE_CONFIG__.${module}.entry]` + + return acc + }, {}) + +Shared module dependencies +-------------------------------------------------------------------------------- + +When building your modules you should review the shared dependency configuration, which by default is defined in the ``src/modules/sharedDeps.js`` file. This script imports the ``package.json`` file for resolving different dependency versions and should be sufficient in most cases. + +.. note:: Not all dependencies are shared between modules. For more information on which dependencies should be shared and how to configure them, you can refer to the official `Module Federation documentation `_. + +.. _importing_remote_modules: + +Importing from other modules +-------------------------------------------------------------------------------- + +In order to import correctly between modules, you should not use relative import paths between them, even if this may seem convenient at first. As this creates a hard-link between the modules, and webpack will bundle parts of them together. Which in turn means that the modules cannot be rebuilt independently of one another. Instead, you should use the following syntax to import from another module: + +``import ... from @`` + +Which should match the key property in the ``configuredRemotes`` object, as mentioned previously in the :ref:`resolving other modules ` section. + +.. _exporting_remote_modules: + +Exporting from a module +-------------------------------------------------------------------------------- + +All remote module exports should be done using a global barrel file. This means that all nested exports should be accessible from the top-level index file of the module. + +.. important:: Default exports should not be used. You should use named exports only, when exposing imports according to the default webpack configuration used :ref:`here `. + +An example of the barrel file from the ``ContainersModule`` + +.. code-block:: javascript + + export * from '@modules/containers/ACLs' + export * from '@modules/containers/BackupJobs' + export * from '@modules/containers/Backups' + export * from '@modules/containers/Clusters' + export * from '@modules/containers/Dashboard' + export * from '@modules/containers/Datastores' + export * from '@modules/containers/Files' + export * from '@modules/containers/Groups' + export * from '@modules/containers/Guacamole' + export * from '@modules/containers/Hosts' + export * from '@modules/containers/Images' + export * from '@modules/containers/Login' + export * from '@modules/containers/MarketplaceApps' + export * from '@modules/containers/Marketplaces' + export * from '@modules/containers/Providers' + export * from '@modules/containers/Provisions' + export * from '@modules/containers/SecurityGroups' + export * from '@modules/containers/ServiceTemplates' + export * from '@modules/containers/Services' + export * from '@modules/containers/Settings' + export * from '@modules/containers/Support' + export * from '@modules/containers/TestApi' + export * from '@modules/containers/TestForm' + export * from '@modules/containers/Users' + export * from '@modules/containers/VDCs' + export * from '@modules/containers/VnTemplates' + export * from '@modules/containers/VirtualMachines' + export * from '@modules/containers/VirtualNetworks' + export * from '@modules/containers/VirtualRouterTemplates' + export * from '@modules/containers/VirtualRouters' + export * from '@modules/containers/VmGroups' + export * from '@modules/containers/VmTemplates' + export * from '@modules/containers/WebMKS' + export * from '@modules/containers/Zones' + +These exports are then being exposed directly from the module namespace. See the `exposes` section under the :ref:`default module webpack ` configuration. + + FireEdge API ================================================================================ @@ -33,7 +704,7 @@ OpenNebula FireEdge API is a RESTful service to communicate with other OpenNebul Among others, it includes the OpenNebula Cloud API Specification for JS. It been designed as a wrapper for the :ref:`XML-RPC methods `, with some basic helpers to return the data in JSON formats. This means that you should be familiar with the XML-RPC API and the JSON formats returned by the OpenNebula core. Authentication & Authorization -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- User authentication is done via XMLRPC using the OpenNebula authorization module. If the username and password matches with the serveradmin data, the user's request will be granted, the session data will be saved in a global variable (cache-nodejs), and a JSON Web Token (JWT) will be generated that must be sent in the authorization header of the HTTP request. @@ -46,7 +717,7 @@ User authentication is done via XMLRPC using the OpenNebula authorization module .. note:: The JWT lifetime can be configured in the fireedge_server.conf configuration file. Methods -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- Auth -------------------------------------------------------------------------------- @@ -154,7 +825,6 @@ Zendesk | **PUT** | ``/fireedge/api/zendesk/`` | **Update** the ticket identified by . | +--------------+---------------------------------------------+----------------------------------------------------+ - Frontend Architecture ================================================================================ @@ -170,7 +840,7 @@ Sunstone Configuration Files Through the configuration files we can define view types and assign them to different groups. Then, we differentiate between the master and view files. Master File -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- This file orchestrates the views according to the user's primary group and it's located in ``etc/sunstone/sunstone-view.yaml``. @@ -188,7 +858,7 @@ In the following example, all groups have access to the user view and ``oneadmin View Directory And Tab Files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- The view directory contains the route or tab files. These tab files, with YAML extension, describe the behavior of each resource list within the application: VMs, Networks, Hosts, etc. @@ -209,7 +879,7 @@ To develop a new tab, it's necessary to understand the structure of the configur Resource -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- Using the view files as a starting point, the interface generates the available routes and defines them in a menu. @@ -227,7 +897,7 @@ Through each tab in the sidebar you can control and manage OpenNebula resources. Actions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- List of actions to operate over the resources: ``refresh``, ``chown``, ``chgrp``, ``lock``, ``unlock``, etc. @@ -240,7 +910,7 @@ There are three action types: All actions are defined in the resource constants. For example, the VM Template's are located in ``src/client/constants/vmTemplate.js`` as ``VM_TEMPLATE_ACTIONS``. Filter -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- This includes the list of criteria to filter each OpenNebula resource pool. @@ -263,7 +933,7 @@ To add one, first it's necessary to implement the filter in the table columns. E } Information Tabs -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- The detailed view of a resource is structured in a tab-like layout. Tabs are defined in the ``index.js`` file of each resource's folder ``src/client/components/Tabs/``. E.g.: The VM Templates tabs are located in ``src/client/components/Tabs/VmTemplate/index.js``. @@ -295,7 +965,7 @@ Each group of actions can filter by hypervisor (**only resources with hypervisor - lxc Dialogs -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- The resource actions that have the ``_dialog`` suffix, need to define their structure in this section. @@ -346,7 +1016,7 @@ See some examples: SSO (Single sign-on) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------------------------------------------------------- With this function you can access the Sunstone UI from the browser without logging in. For this, you need to send the JWT of the user in the ``externalToken`` parameter of the URL. For example: @@ -366,3 +1036,8 @@ For example: $ http://{fireedge}/fireedge/api/auth {"id":200,"message":"OK","data":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIwIiwiYXVkIjoic2VydmVyYWRtaW46b25lYWRtaW4iLCJqdGkiOiJ2SU85ME91VUU5b1RNaXRRVytLYmNqRXZlS252Qnc5c2Ura1pPNlVRdmRjPSIsImlhdCI6MTY1MDI3NTQzMC45MzcsImV4cCI6MTY1MDI4NjIzMH0.AqJGLbCNG470PbjoI4yLqvKNOl1FR4Ui6YlK6pSZddQ","id":"0"}} + + + +.. |image_fallback_editor| image:: /images/fireedge_fallback_editor.png +.. |users_and_groups_tab| image:: /images/users_and_groups_tab.png diff --git a/source/provision_clusters/edge_clusters/scaleway_cluster.rst b/source/provision_clusters/edge_clusters/scaleway_cluster.rst index 0b194cd472..fda63b5b24 100644 --- a/source/provision_clusters/edge_clusters/scaleway_cluster.rst +++ b/source/provision_clusters/edge_clusters/scaleway_cluster.rst @@ -48,5 +48,5 @@ You can also manage AWS and Equinix Clusters using the OneProvision GUI in Sunst |image_fireedge| -.. |image_cluster| image:: /images/scaleway_deployment.png +.. |image_cluster| image:: /images/scaleway-deployment.jpg .. |image_fireedge| image:: /images/oneprovision_fireedge.png