Skip to content

Commit

Permalink
Add extension image load dialog (rancher#9010)
Browse files Browse the repository at this point in the history
Update dialog with repo creation - update docs

Add uninstall for custom images

Add extension images list view

Add image load dialog and uninstall within extension image view

Update publish and bundle scripts for image load - move image page to tab

Add extension container build workflow file to pkg creator

Move plugin server template into extension build scripts

Fix publish script for multiple asset packages

Move ImageList view to separate page - add crd metadata for custom images

Update docs - fix references to images with catalog

Fix wording, cache state badge, masthead breadcrumb, when deleteing resources check for namespaces

Update docs - fix delete repo resource - default cache state

Trim image whitespace - populate extensionUrl

Add experimental badge
  • Loading branch information
jordojordo authored Jun 2, 2023
1 parent e6f0fa5 commit d94e78c
Show file tree
Hide file tree
Showing 34 changed files with 1,909 additions and 306 deletions.
2 changes: 1 addition & 1 deletion cypress/e2e/po/pages/extensions.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export default class ExtensionsPo extends PagePo {
// }

disableExtensionsClick(): Cypress.Chainable {
return new ActionMenuPo(this.self()).clickMenuItem(2);
return new ActionMenuPo(this.self()).clickMenuItem(3);
}

// ------------------ disable extensions OVERALL modal ------------------
Expand Down
2 changes: 0 additions & 2 deletions docusaurus/docs/extensions/advanced.md

This file was deleted.

120 changes: 120 additions & 0 deletions docusaurus/docs/extensions/advanced/air-gapped-environments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Air-gapped Environments

In order to load an extension within an air-gapped instance of Rancher, you will need to import an Extension Catalog Image to provide the extension assets, which are then served within the "Available" tab of the Extensions page and can be installed as normal.

The Extension Catalog Image (ECI) contains the assets of each extension which give the [ui-plugin-operator](https://github.com/rancher/ui-plugin-operator) the necessary files to load an extension into the Rancher Dashboard.

We have implemented an action within the Extensions page to take care of the heavy lifting for you by creating the necessary resources.

> Note: The ECI is comprised of a hardened [SLE BCI](https://registry.suse.com/bci/bci-base-15sp4/index.html) image with an [NGINX](https://nginx.org/en/) service which supplies the minified extension files.
## Prerequisites

Loading an extension into an air-gapped envrionment requires a few prerequisites, namely:

- The Extension needs to be bundled into the ECI
- A registry to house the ECI
- Access to this registry within the air-gapped Cluster

> Note: Any Secrets that are required to authenticate with the registry ***MUST*** be created in the `cattle-ui-plugin-system` namespace.
## Building the Extension Catalog Image

Currently there are two options available for building your extension into an ECI. You can use the predefined Github Workflow, if you plan on housing the extension within a Github repository, or you can manually build and publish your extension to a specified registry.

In either case, the ECI will need to be published to a registry that is accessible from the air-gapped cluster.

### Github Workflow

If using the provided Github workflow with your extension, the extension will be built and published for each package version to the [Github Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) (`ghcr`).

> Note: The extension image that is built will contain Helm charts for each subsequent package (i.e. `./pkg/<EXTENSION_NAME>`). In order to release a new version of a package, the root extension will need to be published with an updated tag within `./package.json`.
Once the extension has been published you will then be able to pull, tag, and push the ECI into your desired registry.

From a machine that has access to both the desired registry and `ghcr.io`, pull the image:

```sh
docker pull ghcr.io/<ORGANIZATION>/ui-extension-<REPO>:<TAG>
```

Then re-tag and push the image to your registry:

```sh
docker tag ghcr.io/<ORGANIZATION>/ui-extension-<REPO>:<TAG> <MY_REGISTRY>/<ORGANIZATION>/ui-extension-<REPO>:TAG
docker push <MY_REGISTRY>/<ORGANIZATION>/ui-extension-<REPO>:TAG
```

Proceed to the [Importing the Extension Catalog Image](#importing-the-catalog-image) step.

### Manual Build

The ECI can also be built manually using the `yarn publish-pkgs -c` command.

___Building Prerequisites___

This method requires a few tools to be installed:

- [make](https://www.gnu.org/software/make/)
- [docker](https://docs.docker.com/get-docker/)
- [go](https://go.dev/dl/)
- [nodejs](https://nodejs.org/en/download) ( >= `12.0.0` < `17.0.0` )
- [yarn](https://yarnpkg.com/getting-started/install)
- [jq](https://stedolan.github.io/jq/)
- [yq](https://github.com/mikefarah/yq/#install) ( >= `4.0.0` )
- [helm](https://helm.sh/docs/intro/install/) ( >= `3.0.0` )

___Running the Build Manually___

To build, simply run the following:

```sh
yarn publish-pkgs -cp -r <REGISTRY> -o <ORGANIZATION>
```

- `-c` - Specifies the script to build the extension as a container image
- `-p` - To push the built image
- `-r` - Specifies the Container Registry
- `-o` - Specifies the Organization name for the image (defaults to 'rancher')

___Additional Script Usage___
```sh
Usage: yarn publish-pkgs [<options>] [plugins]
options:
-p Push container images on build
-f Force building the chart even if it already exists
-r <name> Specify destination container registry for built images
-o <name> Specify destination container registry organization for built images
-i <prefix> Specify prefix for the built container image (default: 'ui-extension-')
-c Build as a container image rather than publishing to Github
-s <repo> Specify destination GitHub repository (org/name) - defaults to the git origin (implies -g)
-b <branch> Specify destination GitHub branch (implies -g)
```
## Importing the Extension Catalog Image
Importing the ECI is fairly straightforward, you will need the Catalog Image Reference from your registry and any secrets necessary to authenticate with the registry.
> Note: Any Secrets that are required to authenticate with the registry ***MUST*** be created in the `cattle-ui-plugin-system` namespace.
Within the Extensions page, select "Manage Extension Catalog" from the action menu in the top right. From here you will be able to see any Extension Catalog Images loaded previously along with their state, name, image used for the deployment, and cache state (used by the `ui-plugin-operator`).
To import an ECI, click on the "Import Extension Catalog" button:
![Manage Catalog Action](../screenshots/manage-catalog-action.png)
Fill out the form within the modal with your Catalog Reference Image URI (for example: `<MY_REGISTRY>/<ORGANIZATION>/ui-extension-<REPO>:TAG`) and any secrets necessary to pull the image.
> Note: If the registry is not supplied within the URI, it will default to `hub.docker.io`.
> Note: If the version of the image is omitted, this will default to `latest`.
![Extension Catalog Import](../screenshots/import-catalog-dialog.png)
The resources mentioned [above](#air-gapped-environments) will be created. You can navigate back to the main Extensions page by selecting breadcrumb link for "Extension" button from the header title in the top left of the screen.
![Navigate Charts List](../screenshots/navigate-chart-list.png)
Within the "Available", tab the newly imported extensions are now available to be installed normally.
![Available Charts](../screenshots/available-charts.png)
2 changes: 1 addition & 1 deletion docusaurus/docs/extensions/extensions-getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ yarn create @rancher/pkg test -w

This will create a `.github` directory within the root folder of your app which will contain the `build-extension.yml` workflow file. Initially the release is gated by a Push or Pull Request targeting the `main` branch. To update your workflow with different events to trigger the workflow, you can find more information in the [Github docs](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows).

> Note: If you wish to build and publish the Helm chart manually or to a specific registry, you can follow the steps listed in the [Advanced section](./advanced#publishing-the-extension-manually).
> Note: If you wish to build and publish the Helm chart manually or to a specific registry, you can follow the steps listed in the [Publishing an Extension section](./publishing#manually-publishing-an-extension).
### Consuming the Helm chart

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docusaurus/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ const sidebars = {
type: 'category',
label: 'Advanced',
items: [
'extensions/advanced/air-gapped-environments',
'extensions/advanced/localization',
'extensions/advanced/hooks',
'extensions/advanced/stores',
Expand Down
44 changes: 44 additions & 0 deletions shell/assets/translations/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3991,12 +3991,14 @@ plugins:
builtin: Built-in
experimental: Experimental
third-party: Third-Party
image: Image
installing: Installing ...
uninstalling: Uninstalling ...
descriptions:
experimental: This Extension is marked as experimental
third-party: This Extension is provided by a Third-Party
built-in: This Extension is built-in
image: This Extension Image has been loaded manually
error:
title: Error loading extension
message: Could not load extension code
Expand Down Expand Up @@ -4026,12 +4028,53 @@ plugins:
available: No Extensions available
installed: No Extensions installed
updates: No updates available for installed Extensions
images: No Extension Images installed
loadError: An error occurred loading the code for this extension
helmError: "An error occurred installing the extension via Helm"
manageRepos: Manage Repositories
manageCharts: Manage Extension Charts
manageCatalog:
label: Manage Extension Catalogs
title: Extension
subtitle: Catalogs
imageLoad:
load: Import Extension Catalog
prompt: An Extension Catalog contains extension assets bundled into an image, importing will take the image and host a Helm repository to act as a catalog for custom built Extensions.
fields:
image:
label: Catalog Image Reference
placeholder: "e.g. hub.docker.io/example-org/my-image:latest"
secrets:
banner: "If the registry that hosts the Catalog Image requires Pull Secrets, they must be created in the following namespace:<pre>cattle-ui-plugin-system</pre>"
banner: This will create an Deployment, Service, and Helm repository to serve the extension charts.
imageVersion:
title: Image Version Not Found
message: Unable to determine image version from {image}, defaulting to latest
error:
exists:
deployment:
title: Deployment Conflict
message: A container with the image {image} already exists
service:
title: Service Conflict
message: A service with the name {svc} already exists
repo:
title: Helm Repository Conflict
message: A repository with the name {repo} already exists
success:
title: "Imported Extension Catalog from: {name}"
message: Extension Catalog image was imported successfully
headers:
image:
name: images
label: Deployment Image
cacheState:
name: cacheState
label: Cache State
tabs:
all: All
available: Available
images: Images
installed: Installed
updates: Updates
title: Extensions
Expand All @@ -4054,6 +4097,7 @@ plugins:
label: Uninstall
title: "Uninstall Extension: {name}"
prompt: "Are you sure that you want to uninstall this Extension?"
custom: "Are you sure that you want to uninstall this Extension Image? This will also remove any Extensions provided by this image."
upgradeAvailable: A newer version of this Extension is available
reload: Extensions changed - reload required
safeMode:
Expand Down
2 changes: 1 addition & 1 deletion shell/components/ActionMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default {
customTargetEvent: {
// The event details from the user's click can be used
// for positioning the menu on the page.
type: PointerEvent,
type: [PointerEvent, MouseEvent],
default: null
},
Expand Down
74 changes: 74 additions & 0 deletions shell/components/formatter/ExtensionCache.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<script>
import { BadgeState } from '@components/BadgeState';
import { stateDisplay } from '@shell/plugins/dashboard-store/resource-class';
export default {
props: {
value: {
type: String,
default: ''
}
},
components: { BadgeState },
data() {
const STATES = {
cached: {
color: 'info', icon: 'dot-open', label: 'Cached', compoundIcon: 'checkmark'
},
pending: {
color: 'warning', icon: 'tag', label: 'In Progress', compoundIcon: 'info'
},
disabled: {
color: 'error', icon: 'dot-half', label: 'Cache Disabled', compoundIcon: 'info'
},
};
return {
STATES,
stateDisplay: '',
stateBackground: ''
};
},
watch: {
value: {
handler() {
const out = this.value || 'pending';
const color = this.colorForState(out);
this.stateDisplay = stateDisplay(out);
this.stateBackground = color.replace('text-', 'bg-');
},
immediate: true
}
},
methods: {
colorForState(state) {
const key = (state).toLowerCase();
let color;
if ( this.STATES[key] && this.STATES[key].color ) {
color = this.STATES[key].color;
}
if ( !color ) {
color = 'info';
}
return `text-${ color }`;
}
}
};
</script>

<template>
<div>
<BadgeState
:color="stateBackground"
:label="stateDisplay"
/>
</div>
</template>
33 changes: 33 additions & 0 deletions shell/config/table-headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -969,3 +969,36 @@ export const FLEET_BUNDLE_TYPE = {
sort: ['bundleType'],
width: 100,
};

export const UI_PLUGIN_CATALOG = [
{
name: 'state',
labelKey: 'tableHeaders.state',
sort: ['stateSort', 'nameSort'],
value: 'state',
width: 100,
default: 'unknown',
formatter: 'BadgeStateFormatter',
formatterOpts: { arbitrary: true }
},
{
name: 'name',
labelKey: 'tableHeaders.name',
value: 'name',
sort: ['nameSort'],
formatter: 'LinkDetail'
},
{
name: 'image',
sort: ['image'],
labelKey: 'plugins.manageCatalog.headers.image.label',
value: 'deploymentImage'
},
{
name: 'cacheState',
sort: ['cacheState'],
labelKey: 'plugins.manageCatalog.headers.cacheState.label',
value: 'cacheState',
formatter: 'ExtensionCache'
}
];
11 changes: 11 additions & 0 deletions shell/config/uiplugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ export const UI_PLUGIN_CHART_ANNOTATIONS = {
DISPLAY_NAME: 'catalog.cattle.io/display-name',
};

// Extension catalog labels
export const UI_PLUGIN_LABELS = {
CATALOG_IMAGE: 'catalog.cattle.io/ui-extensions-catalog-image',
REPOSITORY: 'catalog.cattle.io/ui-extensions-repository',
CATALOG: 'catalog.cattle.io/ui-extensions-catalog'
};

// Plugin Metadata properties
export const UI_PLUGIN_METADATA = {
RANCHER_VERSION: 'rancherVersion',
Expand Down Expand Up @@ -99,6 +106,10 @@ export function shouldNotLoadPlugin(plugin, rancherVersion) {
}
}

if (plugin.metadata?.[UI_PLUGIN_LABELS.CATALOG]) {
return true;
}

return false;
}

Expand Down
Loading

0 comments on commit d94e78c

Please sign in to comment.