mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-10-06 14:16:05 +08:00
Compare commits
83
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8b4ee4c41 | ||
|
|
021d6f673f | ||
|
|
a849671034 | ||
|
|
b98f878c5d | ||
|
|
78482285b3 | ||
|
|
4656976b91 | ||
|
|
aeb3588b83 | ||
|
|
d14b0cb95c | ||
|
|
2f0884d7bd | ||
|
|
037ce6132b | ||
|
|
47b54b4f06 | ||
|
|
9dd8ae479a | ||
|
|
5682bf4c3a | ||
|
|
960df31667 | ||
|
|
63451e7d2b | ||
|
|
55aaa8440d | ||
|
|
da4121da69 | ||
|
|
30e49a6f2c | ||
|
|
2255bd4f69 | ||
|
|
7e5ee04637 | ||
|
|
8863de8874 | ||
|
|
73952a6b4e | ||
|
|
0496fae623 | ||
|
|
d5cd97aafd | ||
|
|
31c6a794be | ||
|
|
9d9383ba90 | ||
|
|
1e02dbffe3 | ||
|
|
b0609020cc | ||
|
|
feca476e36 | ||
|
|
e6e36e94f1 | ||
|
|
54d48ce396 | ||
|
|
404395c7d9 | ||
|
|
dc2437db99 | ||
|
|
e8c8a54b9f | ||
|
|
f3e4a8afe8 | ||
|
|
e73c62739f | ||
|
|
696af4e04f | ||
|
|
009f384a73 | ||
|
|
37766454bd | ||
|
|
7943913ef7 | ||
|
|
56a0fefd40 | ||
|
|
ff1d5925a8 | ||
|
|
63b5b980b7 | ||
|
|
1f7fd1246f | ||
|
|
34a25e9fc8 | ||
|
|
fb8d81d953 | ||
|
|
ba810a52b2 | ||
|
|
3f4f30ba0b | ||
|
|
b428aaecf8 | ||
|
|
6b07a03451 | ||
|
|
2c756582e3 | ||
|
|
1c15ed8003 | ||
|
|
9f3e689727 | ||
|
|
6644651fe5 | ||
|
|
2d6bc65b26 | ||
|
|
7b6efa624f | ||
|
|
d9db1263d1 | ||
|
|
10a8f18784 | ||
|
|
1098ef8f6a | ||
|
|
4480dbdeed | ||
|
|
a7b4366d7c | ||
|
|
d72857f374 | ||
|
|
57ab9e2830 | ||
|
|
8116358011 | ||
|
|
5bd8ad2a93 | ||
|
|
345fe636ec | ||
|
|
7e32ea453b | ||
|
|
8f3b5265de | ||
|
|
4ca6caefb9 | ||
|
|
fb7d604ed6 | ||
|
|
9a60a621de | ||
|
|
7645d6161f | ||
|
|
c3f2665912 | ||
|
|
2a58745550 | ||
|
|
69d7046bc7 | ||
|
|
692c775b51 | ||
|
|
8b43c200b2 | ||
|
|
ab71cb377c | ||
|
|
814d296d75 | ||
|
|
eb667fd56b | ||
|
|
e4b3f84905 | ||
|
|
ea68b95c26 | ||
|
|
da77762b7f |
@@ -0,0 +1,35 @@
|
|||||||
|
name: Build Harvester Catalog Image and Publish on Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
uses: ./.github/actions/lint
|
||||||
|
|
||||||
|
build-and-push-extension-catalog:
|
||||||
|
needs: lint
|
||||||
|
uses: ./.github/workflows/build-extension-catalog.yml
|
||||||
|
permissions:
|
||||||
|
actions: write
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
with:
|
||||||
|
registry_target: docker.io
|
||||||
|
registry_user: rancher
|
||||||
|
secrets: inherit
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
name: Build Harvester Dashboard and Upload
|
name: Build Harvester Dashboard and Publish
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
name: Build and release Extension Catalog Image to registry
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
registry_target:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
registry_user:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
outputs:
|
||||||
|
build-extension-catalog-job-status:
|
||||||
|
value: ${{ jobs.build-extension-catalog.outputs.build-status }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push-extension-catalog:
|
||||||
|
name: Build container image
|
||||||
|
if: github.ref_type == 'tag' || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: write
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
outputs:
|
||||||
|
build-status: ${{ job.status }}
|
||||||
|
steps:
|
||||||
|
- name: Read Secrets
|
||||||
|
uses: rancher-eio/read-vault-secrets@main
|
||||||
|
with:
|
||||||
|
secrets: |
|
||||||
|
secret/data/github/repo/${{ github.repository }}/dockerhub/rancher/credentials username | DOCKER_USERNAME ;
|
||||||
|
secret/data/github/repo/${{ github.repository }}/dockerhub/rancher/credentials password | DOCKER_PASSWORD ;
|
||||||
|
|
||||||
|
- name: Checkout repository (normal flow)
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Enable Corepack
|
||||||
|
run: corepack enable
|
||||||
|
|
||||||
|
- name: Configure Git
|
||||||
|
run: |
|
||||||
|
git config user.name 'github-actions[bot]'
|
||||||
|
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ env.DOCKER_USERNAME }}
|
||||||
|
password: ${{ env.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Setup Helm
|
||||||
|
uses: azure/setup-helm@v3
|
||||||
|
with:
|
||||||
|
version: v3.8.0
|
||||||
|
|
||||||
|
- name: Setup Nodejs with yarn caching
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn
|
||||||
|
|
||||||
|
- name: Build and push UI image
|
||||||
|
run: |
|
||||||
|
publish="yarn publish-pkgs -cp -r ${{ inputs.registry_target }} -o ${{ inputs.registry_user }}"
|
||||||
|
$publish
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
name: Build and Release Extension Charts
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [released]
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
working-directory: ./
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
uses: ./.github/actions/lint
|
|
||||||
build-extension-charts:
|
|
||||||
needs:
|
|
||||||
- lint
|
|
||||||
uses: rancher/dashboard/.github/workflows/build-extension-charts.yml@master
|
|
||||||
permissions:
|
|
||||||
actions: write
|
|
||||||
contents: write
|
|
||||||
deployments: write
|
|
||||||
pages: write
|
|
||||||
with:
|
|
||||||
target_branch: gh-pages
|
|
||||||
tagged_release: ${{ github.ref_name }}
|
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
name: Build and Release Extension Charts on PR Merge
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'release-harvester-v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
setup-target-branch:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
target_branch: ${{ steps.get-version.outputs.target_branch }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Determine target branch
|
||||||
|
id: get-version
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref_name }}" =~ ^release-harvester-v([0-9]+\.[0-9]+)$ ]]; then
|
||||||
|
TARGET_BRANCH="v${BASH_REMATCH[1]}-head"
|
||||||
|
echo "target_branch=${TARGET_BRANCH}" >> $GITHUB_ENV
|
||||||
|
echo "target_branch=${TARGET_BRANCH}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "Error: invalid branch format." && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Ensure target branch exists
|
||||||
|
run: |
|
||||||
|
git fetch --all
|
||||||
|
if ! git ls-remote --exit-code --heads origin "${{ env.target_branch }}"; then
|
||||||
|
git checkout gh-pages
|
||||||
|
git checkout -b "${{ env.target_branch }}"
|
||||||
|
git push origin "${{ env.target_branch }}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
extract-version:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.get_version.outputs.version }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Extract version from package.json
|
||||||
|
id: get_version
|
||||||
|
run: |
|
||||||
|
VERSION=$(jq -r '.version' pkg/harvester/package.json)
|
||||||
|
echo "VERSION=${VERSION}" >> $GITHUB_ENV
|
||||||
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
build-extension-charts:
|
||||||
|
needs:
|
||||||
|
- setup-target-branch
|
||||||
|
- extract-version
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup environment
|
||||||
|
run: |
|
||||||
|
corepack enable
|
||||||
|
yarn install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Setup Helm
|
||||||
|
uses: azure/setup-helm@v3
|
||||||
|
with:
|
||||||
|
version: v3.8.0
|
||||||
|
|
||||||
|
- name: Build Helm charts
|
||||||
|
run: |
|
||||||
|
yarn publish-pkgs -s ${{ github.repository }} -b ${{ needs.setup-target-branch.outputs.target_branch }} -t harvester-${{ needs.extract-version.outputs.version }}
|
||||||
|
|
||||||
|
- name: Upload charts artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: charts
|
||||||
|
path: tmp
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs:
|
||||||
|
- setup-target-branch
|
||||||
|
- extract-version
|
||||||
|
- build-extension-charts
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout release branch
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: '${{ github.ref_name }}'
|
||||||
|
|
||||||
|
- name: Get last commit hash
|
||||||
|
id: last_commit
|
||||||
|
run: |
|
||||||
|
LAST_COMMIT=$(git rev-parse HEAD)
|
||||||
|
echo "LAST_COMMIT=${LAST_COMMIT}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Checkout target branch
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: '${{ needs.setup-target-branch.outputs.target_branch }}'
|
||||||
|
|
||||||
|
- name: Remove old artifacts
|
||||||
|
run: |
|
||||||
|
rm -rf extensions/harvester/${{ needs.extract-version.outputs.version }}
|
||||||
|
rm -rf charts/harvester/${{ needs.extract-version.outputs.version }}
|
||||||
|
rm -f assets/harvester/harvester-${{ needs.extract-version.outputs.version }}.tgz
|
||||||
|
|
||||||
|
- name: Configure Git
|
||||||
|
run: |
|
||||||
|
git config user.name 'github-actions[bot]'
|
||||||
|
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
||||||
|
|
||||||
|
- name: Download build artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: charts
|
||||||
|
|
||||||
|
- name: Commit and push artifacts
|
||||||
|
run: |
|
||||||
|
git add ./{assets,charts,extensions,index.yaml}
|
||||||
|
git commit -m "CI Build Artifacts (commit: ${{ env.LAST_COMMIT }}, version: ${{ needs.extract-version.outputs.version }})"
|
||||||
|
git push origin ${{ needs.setup-target-branch.outputs.target_branch }}
|
||||||
|
|
||||||
|
- name: Run Helm chart releaser
|
||||||
|
uses: helm/chart-releaser-action@v1.4.1
|
||||||
|
with:
|
||||||
|
charts_dir: ./charts
|
||||||
|
env:
|
||||||
|
CR_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
|
CR_SKIP_EXISTING: true
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
name: Build and Release Extension Charts on Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [released]
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
setup-release-tag:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
release_tag: ${{ steps.determine_tag.outputs.release_tag }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Determine release tag
|
||||||
|
id: determine_tag
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref_name }}" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
|
||||||
|
RELEASE_TAG="harvester-${BASH_REMATCH[1]}"
|
||||||
|
echo "${RELEASE_TAG}"
|
||||||
|
echo "release_tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "Error: invalid tag format." && exit 1
|
||||||
|
fi
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
uses: ./.github/actions/lint
|
||||||
|
build-extension-charts:
|
||||||
|
needs:
|
||||||
|
- setup-release-tag
|
||||||
|
- lint
|
||||||
|
uses: rancher/dashboard/.github/workflows/build-extension-charts.yml@master
|
||||||
|
permissions:
|
||||||
|
actions: write
|
||||||
|
contents: write
|
||||||
|
deployments: write
|
||||||
|
pages: write
|
||||||
|
with:
|
||||||
|
target_branch: gh-pages
|
||||||
|
tagged_release: '${{ needs.setup-release-tag.outputs.release_tag }}'
|
||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
name: Build Dashboard (Branch)
|
name: Build Standalone on PR Merge
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -17,10 +17,10 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-validation:
|
build-validation:
|
||||||
name: Build Test
|
name: Build Test
|
||||||
uses: ./.github/workflows/test.yaml
|
uses: ./.github/workflows/run-lint.yaml
|
||||||
build:
|
build:
|
||||||
name: Build and Upload Package
|
name: Build and Upload Package
|
||||||
uses: ./.github/workflows/build-and-upload.yaml
|
uses: ./.github/workflows/build-and-publish-standalone.yaml
|
||||||
needs:
|
needs:
|
||||||
- build-validation
|
- build-validation
|
||||||
permissions:
|
permissions:
|
||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
name: Build Dashboard (Release)
|
name: Build Standalone on Release
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
@@ -7,10 +7,10 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-validation:
|
build-validation:
|
||||||
name: Build Test
|
name: Build Test
|
||||||
uses: ./.github/workflows/test.yaml
|
uses: ./.github/workflows/run-lint.yaml
|
||||||
build:
|
build:
|
||||||
name: Build and Upload Package
|
name: Build and Upload Package
|
||||||
uses: ./.github/workflows/build-and-upload.yaml
|
uses: ./.github/workflows/build-and-publish-standalone.yaml
|
||||||
needs:
|
needs:
|
||||||
- build-validation
|
- build-validation
|
||||||
permissions:
|
permissions:
|
||||||
@@ -70,7 +70,7 @@ For developers, after reading through the introduction on this page, head over t
|
|||||||
|
|
||||||
License
|
License
|
||||||
=======
|
=======
|
||||||
Copyright (c) 2014-2025 [SUSE, LLC.](https://www.suse.com/)
|
Copyright (c) 2014-2023 [Rancher Labs, Inc.](http://rancher.com)
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|||||||
+4
-4
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "harvester-ui-extension",
|
"name": "harvester-ui-extension",
|
||||||
"version": "0.1.0",
|
"version": "1.0.6",
|
||||||
"private": false,
|
"private": false,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rancher/shell": "3.0.2-rc.3",
|
"@rancher/shell": "3.0.1-rc.4",
|
||||||
"cache-loader": "^4.1.0",
|
"cache-loader": "^4.1.0",
|
||||||
"color": "4.2.3",
|
"color": "4.2.3",
|
||||||
"ip": "2.0.1",
|
"ip": "2.0.1",
|
||||||
@@ -19,8 +19,8 @@
|
|||||||
"@types/node": "~20.10.0",
|
"@types/node": "~20.10.0",
|
||||||
"cronstrue": "2.50.0",
|
"cronstrue": "2.50.0",
|
||||||
"d3-color": "3.1.0",
|
"d3-color": "3.1.0",
|
||||||
"ejs": "3.1.9",
|
"ejs": "3.1.10",
|
||||||
"follow-redirects": "1.15.2",
|
"follow-redirects": "1.15.6",
|
||||||
"glob": "7.2.3",
|
"glob": "7.2.3",
|
||||||
"glob-parent": "6.0.2",
|
"glob-parent": "6.0.2",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
|
|||||||
@@ -5,10 +5,8 @@ import { Checkbox } from '@components/Form/Checkbox';
|
|||||||
import ModalWithCard from '@shell/components/ModalWithCard';
|
import ModalWithCard from '@shell/components/ModalWithCard';
|
||||||
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||||
import { Banner } from '@components/Banner';
|
import { Banner } from '@components/Banner';
|
||||||
import { HCI as HCI_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations';
|
|
||||||
import { HCI } from '../types';
|
import { HCI } from '../types';
|
||||||
import UpgradeInfo from './UpgradeInfo';
|
import UpgradeInfo from './UpgradeInfo';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'HarvesterUpgrade',
|
name: 'HarvesterUpgrade',
|
||||||
|
|
||||||
@@ -30,15 +28,14 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
upgrade: [],
|
upgrade: [],
|
||||||
upgradeMessage: [],
|
upgradeMessage: [],
|
||||||
errors: '',
|
errors: '',
|
||||||
selectMode: true,
|
selectMode: true,
|
||||||
version: '',
|
version: '',
|
||||||
enableLogging: true,
|
enableLogging: true,
|
||||||
skipSingleReplicaDetachedVol: false,
|
readyReleaseNote: false,
|
||||||
readyReleaseNote: false,
|
isOpen: false
|
||||||
isOpen: false
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -71,10 +68,6 @@ export default {
|
|||||||
return this.$store.getters['harvester/schemaFor'](HCI.UPGRADE_LOG);
|
return this.$store.getters['harvester/schemaFor'](HCI.UPGRADE_LOG);
|
||||||
},
|
},
|
||||||
|
|
||||||
skipSingleReplicaDetachedVolFeatureEnabled() {
|
|
||||||
return this.$store.getters['harvester-common/getFeatureEnabled']('skipSingleReplicaDetachedVol');
|
|
||||||
},
|
|
||||||
|
|
||||||
releaseLink() {
|
releaseLink() {
|
||||||
return `https://github.com/harvester/harvester/releases/tag/${ this.version }`;
|
return `https://github.com/harvester/harvester/releases/tag/${ this.version }`;
|
||||||
}
|
}
|
||||||
@@ -111,11 +104,6 @@ export default {
|
|||||||
spec: { version: this.version }
|
spec: { version: this.version }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.skipSingleReplicaDetachedVolFeatureEnabled && this.skipSingleReplicaDetachedVol) {
|
|
||||||
upgradeValue.metadata.annotations =
|
|
||||||
{ [HCI_ANNOTATIONS.SKIP_SINGLE_REPLICA_DETACHED_VOL]: JSON.stringify(this.skipSingleReplicaDetachedVol) };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.canEnableLogging) {
|
if (this.canEnableLogging) {
|
||||||
upgradeValue.spec.logEnabled = this.enableLogging;
|
upgradeValue.spec.logEnabled = this.enableLogging;
|
||||||
}
|
}
|
||||||
@@ -202,21 +190,6 @@ export default {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="skipSingleReplicaDetachedVolFeatureEnabled"
|
|
||||||
class="mb-5"
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
v-model:value="skipSingleReplicaDetachedVol"
|
|
||||||
class="check"
|
|
||||||
type="checkbox"
|
|
||||||
:label="t('harvester.upgradePage.skipSingleReplicaDetachedVol')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<hr
|
|
||||||
v-if="version"
|
|
||||||
class="divider"
|
|
||||||
/>
|
|
||||||
<div v-if="version">
|
<div v-if="version">
|
||||||
<p
|
<p
|
||||||
v-clean-html="t('harvester.upgradePage.releaseTip', {url: releaseLink}, true)"
|
v-clean-html="t('harvester.upgradePage.releaseTip', {url: releaseLink}, true)"
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ export default {
|
|||||||
v-clean-tooltip="{
|
v-clean-tooltip="{
|
||||||
placement: 'bottom-left',
|
placement: 'bottom-left',
|
||||||
}"
|
}"
|
||||||
|
popper-class="upgrade-header-dropdown"
|
||||||
class="hand"
|
class="hand"
|
||||||
>
|
>
|
||||||
<slot name="button-content">
|
<slot name="button-content">
|
||||||
@@ -272,7 +273,7 @@ export default {
|
|||||||
|
|
||||||
<p
|
<p
|
||||||
v-if="overallMessage"
|
v-if="overallMessage"
|
||||||
class="text-warning mb-20"
|
class="text-error mb-20"
|
||||||
>
|
>
|
||||||
{{ overallMessage }}
|
{{ overallMessage }}
|
||||||
</p>
|
</p>
|
||||||
@@ -300,14 +301,14 @@ export default {
|
|||||||
|
|
||||||
<ProgressBarList
|
<ProgressBarList
|
||||||
:title="t('harvester.upgradePage.upgradeNode')"
|
:title="t('harvester.upgradePage.upgradeNode')"
|
||||||
:precent="nodesPercent"
|
:percent="nodesPercent"
|
||||||
:list="nodesStatus"
|
:list="nodesStatus"
|
||||||
/>
|
/>
|
||||||
<p class="bordered-section"></p>
|
<p class="bordered-section"></p>
|
||||||
|
|
||||||
<ProgressBarList
|
<ProgressBarList
|
||||||
:title="t('harvester.upgradePage.upgradeSysService')"
|
:title="t('harvester.upgradePage.upgradeSysService')"
|
||||||
:precent="sysServiceTotal"
|
:percent="sysServiceTotal"
|
||||||
:list="sysServiceUpgradeMessage"
|
:list="sysServiceUpgradeMessage"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -338,6 +339,12 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.upgrade-header-dropdown .v-popper__arrow-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
a {
|
a {
|
||||||
float: right;
|
float: right;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default {
|
|||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
precent: {
|
percent: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
},
|
},
|
||||||
@@ -39,16 +39,18 @@ export default {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bar-list">
|
<div class="bar-list">
|
||||||
<h4>{{ title }} <span class="float-r text-info">{{ precent }}%</span></h4>
|
<h4>{{ title }} <span class="float-r text-info">{{ percent }}%</span></h4>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<Collapse v-model:open="open">
|
<Collapse v-model:open="open">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="total-bar">
|
<div class="total-bar">
|
||||||
<span class="bar"><PercentageBar
|
<span class="bar">
|
||||||
:model-value="precent"
|
<PercentageBar
|
||||||
preferred-direction="MORE"
|
:model-value="percent"
|
||||||
/></span>
|
preferred-direction="MORE"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
class="on-off"
|
class="on-off"
|
||||||
@click="handleSwitch"
|
@click="handleSwitch"
|
||||||
@@ -56,28 +58,26 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template>
|
<div class="custom-content">
|
||||||
<div class="custom-content">
|
<div
|
||||||
<div
|
v-for="(item, i) in list"
|
||||||
v-for="(item, i) in list"
|
:key="i"
|
||||||
:key="i"
|
>
|
||||||
>
|
<p>
|
||||||
<p>
|
{{ item.name }} <span
|
||||||
{{ item.name }} <span
|
class="status"
|
||||||
class="status"
|
:class="{ [item.state]: true }"
|
||||||
:class="{ [item.state]: true }"
|
>{{ item.state }}</span>
|
||||||
>{{ item.state }}</span>
|
</p>
|
||||||
</p>
|
<PercentageBar
|
||||||
<PercentageBar
|
:model-value="item.percent"
|
||||||
:model-value="item.percent"
|
preferred-direction="MORE"
|
||||||
preferred-direction="MORE"
|
/>
|
||||||
/>
|
<p class="warning">
|
||||||
<p class="warning">
|
{{ item.message }}
|
||||||
{{ item.message }}
|
</p>
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -93,7 +93,7 @@ export default {
|
|||||||
.total-bar {
|
.total-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
.bar {
|
> .bar {
|
||||||
width: 85%;
|
width: 85%;
|
||||||
}
|
}
|
||||||
.on-off {
|
.on-off {
|
||||||
@@ -102,25 +102,22 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.custom-content {
|
.custom-content {
|
||||||
.item {
|
margin-bottom: 14px;
|
||||||
margin-bottom: 14px;
|
p {
|
||||||
p {
|
margin-bottom: 4px;
|
||||||
margin-bottom: 4px;
|
}
|
||||||
}
|
.status {
|
||||||
.status {
|
float: right;
|
||||||
float: right;
|
}
|
||||||
}
|
.Succeeded, .Upgrading, .Pending {
|
||||||
.Succeeded, .Upgrading, .Pending {
|
color: var(--success);
|
||||||
color: var(--success);
|
}
|
||||||
}
|
.failed {
|
||||||
.failed {
|
color: var(--error)
|
||||||
color: var(--error)
|
}
|
||||||
}
|
.warning {
|
||||||
.warning {
|
color: var(--error);
|
||||||
color: var(--error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import CreateEditView from '@shell/mixins/create-edit-view';
|
|||||||
import { LabeledInput } from '@components/Form/LabeledInput';
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||||
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||||
import { HCI_SETTING } from '../../config/settings';
|
import { HCI_SETTING } from '../../config/settings';
|
||||||
|
import UnitInput from '@shell/components/form/UnitInput';
|
||||||
|
|
||||||
const DEFAULT_TYPE = 's3';
|
const DEFAULT_TYPE = 's3';
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ export default {
|
|||||||
name: 'HarvesterEditBackupTarget',
|
name: 'HarvesterEditBackupTarget',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
LabeledInput, LabeledSelect, Tip, Password, MessageLink
|
LabeledInput, LabeledSelect, Tip, Password, MessageLink, UnitInput
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [CreateEditView],
|
mixins: [CreateEditView],
|
||||||
@@ -24,7 +25,9 @@ export default {
|
|||||||
try {
|
try {
|
||||||
parseDefaultValue = JSON.parse(this.value.value);
|
parseDefaultValue = JSON.parse(this.value.value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
parseDefaultValue = { type: '', endpoint: '' };
|
parseDefaultValue = {
|
||||||
|
type: '', endpoint: '', refreshIntervalInSeconds: 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// set default type to s3
|
// set default type to s3
|
||||||
@@ -62,6 +65,10 @@ export default {
|
|||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
refreshIntervalInSecondEnabled() {
|
||||||
|
return this.$store.getters['harvester-common/getFeatureEnabled']('refreshIntervalInSecond');
|
||||||
|
},
|
||||||
|
|
||||||
isS3() {
|
isS3() {
|
||||||
return this.parseDefaultValue.type === DEFAULT_TYPE;
|
return this.parseDefaultValue.type === DEFAULT_TYPE;
|
||||||
},
|
},
|
||||||
@@ -83,7 +90,9 @@ export default {
|
|||||||
try {
|
try {
|
||||||
parseDefaultValue = JSON.parse(neu.value);
|
parseDefaultValue = JSON.parse(neu.value);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
parseDefaultValue = { type: '', endpoint: '' };
|
parseDefaultValue = {
|
||||||
|
type: '', endpoint: '', refreshIntervalInSeconds: 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
this['parseDefaultValue'] = parseDefaultValue;
|
this['parseDefaultValue'] = parseDefaultValue;
|
||||||
@@ -111,7 +120,6 @@ export default {
|
|||||||
if (this.isS3 && !this.parseDefaultValue.virtualHostedStyle) {
|
if (this.isS3 && !this.parseDefaultValue.virtualHostedStyle) {
|
||||||
this.parseDefaultValue.virtualHostedStyle = false;
|
this.parseDefaultValue.virtualHostedStyle = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.parseDefaultValue.type) {
|
if (!this.parseDefaultValue.type) {
|
||||||
delete this.value['value'];
|
delete this.value['value'];
|
||||||
} else {
|
} else {
|
||||||
@@ -120,7 +128,9 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
useDefault() {
|
useDefault() {
|
||||||
this['parseDefaultValue'] = { type: '', endpoint: '' };
|
this['parseDefaultValue'] = {
|
||||||
|
type: '', endpoint: '', refreshIntervalInSeconds: 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -139,6 +149,23 @@ export default {
|
|||||||
:options="typeOption"
|
:options="typeOption"
|
||||||
@update:value="update"
|
@update:value="update"
|
||||||
/>
|
/>
|
||||||
|
<UnitInput
|
||||||
|
v-if="refreshIntervalInSecondEnabled"
|
||||||
|
v-model:value="parseDefaultValue.refreshIntervalInSeconds"
|
||||||
|
:suffix="parseDefaultValue.refreshIntervalInSeconds <= 1 ? 'Second' : 'Seconds'"
|
||||||
|
:label="t('harvester.backup.refreshInterval.label')"
|
||||||
|
:mode="mode"
|
||||||
|
:positive="true"
|
||||||
|
class="mb-5"
|
||||||
|
required
|
||||||
|
@update:value="update"
|
||||||
|
/>
|
||||||
|
<Tip
|
||||||
|
v-if="refreshIntervalInSecondEnabled"
|
||||||
|
class="mb-20"
|
||||||
|
icon="icon icon-info"
|
||||||
|
:text="t('harvester.backup.refreshInterval.tip')"
|
||||||
|
/>
|
||||||
<LabeledInput
|
<LabeledInput
|
||||||
v-model:value="parseDefaultValue.endpoint"
|
v-model:value="parseDefaultValue.endpoint"
|
||||||
class="mb-5"
|
class="mb-5"
|
||||||
|
|||||||
@@ -75,7 +75,11 @@ export default {
|
|||||||
const csiDrivers = this.$store.getters[`${ inStore }/all`](CSI_DRIVER) || [];
|
const csiDrivers = this.$store.getters[`${ inStore }/all`](CSI_DRIVER) || [];
|
||||||
|
|
||||||
return this.configArr.length >= csiDrivers.length;
|
return this.configArr.length >= csiDrivers.length;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
allowEmptySnapshotClassNameFeatureEnabled() {
|
||||||
|
return this.$store.getters['harvester-common/getFeatureEnabled']('allowEmptySnapshotClassName');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -139,7 +143,7 @@ export default {
|
|||||||
errors.push(this.t('validation.required', { key: this.t('harvester.setting.csiDriverConfig.volumeSnapshotClassName') }, true));
|
errors.push(this.t('validation.required', { key: this.t('harvester.setting.csiDriverConfig.volumeSnapshotClassName') }, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.value.backupVolumeSnapshotClassName) {
|
if (!this.allowEmptySnapshotClassNameFeatureEnabled && !config.value.backupVolumeSnapshotClassName) {
|
||||||
errors.push(this.t('validation.required', { key: this.t('harvester.setting.csiDriverConfig.backupVolumeSnapshotClassName') }, true));
|
errors.push(this.t('validation.required', { key: this.t('harvester.setting.csiDriverConfig.backupVolumeSnapshotClassName') }, true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -158,10 +162,22 @@ export default {
|
|||||||
this.configArr.splice(idx, 1);
|
this.configArr.splice(idx, 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isBackupVolumeSnapshotRequired(driver) {
|
||||||
|
return driver === LONGHORN_DRIVER;
|
||||||
|
},
|
||||||
|
|
||||||
disableEdit(driver) {
|
disableEdit(driver) {
|
||||||
return driver === LONGHORN_DRIVER;
|
return driver === LONGHORN_DRIVER;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isBackupVolumeSnapshotClassNameDisabled(driver) {
|
||||||
|
return driver === LONGHORN_DRIVER || this.allowEmptySnapshotClassNameFeatureEnabled;
|
||||||
|
},
|
||||||
|
|
||||||
|
isBackupVolumeSnapshotClassNameSelectable(driver) {
|
||||||
|
return driver === LONGHORN_DRIVER;
|
||||||
|
},
|
||||||
|
|
||||||
add() {
|
add() {
|
||||||
this.configArr.push({
|
this.configArr.push({
|
||||||
key: '',
|
key: '',
|
||||||
@@ -184,6 +200,7 @@ export default {
|
|||||||
<InfoBox
|
<InfoBox
|
||||||
v-for="(driver, idx) in configArr"
|
v-for="(driver, idx) in configArr"
|
||||||
:key="idx"
|
:key="idx"
|
||||||
|
class="box"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
:disabled="disableEdit(driver.key)"
|
:disabled="disableEdit(driver.key)"
|
||||||
@@ -226,10 +243,11 @@ export default {
|
|||||||
<LabeledSelect
|
<LabeledSelect
|
||||||
v-model:value="driver.value.backupVolumeSnapshotClassName"
|
v-model:value="driver.value.backupVolumeSnapshotClassName"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
required
|
:disabled="isBackupVolumeSnapshotClassNameDisabled(driver.key)"
|
||||||
:disabled="disableEdit(driver.key)"
|
|
||||||
:options="getVolumeSnapshotOptions(driver.key)"
|
:options="getVolumeSnapshotOptions(driver.key)"
|
||||||
|
:required="isBackupVolumeSnapshotRequired(driver.key)"
|
||||||
:label="t('harvester.setting.csiDriverConfig.backupVolumeSnapshotClassName')"
|
:label="t('harvester.setting.csiDriverConfig.backupVolumeSnapshotClassName')"
|
||||||
|
@selectable="isBackupVolumeSnapshotClassNameSelectable(driver.key)"
|
||||||
@keydown.native.enter.prevent="()=>{}"
|
@keydown.native.enter.prevent="()=>{}"
|
||||||
@update:value="update"
|
@update:value="update"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ import { NODE } from '@shell/config/types';
|
|||||||
import { HCI } from '../../types';
|
import { HCI } from '../../types';
|
||||||
import { DOC } from '../../config/doc-links';
|
import { DOC } from '../../config/doc-links';
|
||||||
import { docLink } from '../../utils/feature-flags';
|
import { docLink } from '../../utils/feature-flags';
|
||||||
import { NETWORK_TYPE } from '../../config/types';
|
|
||||||
|
|
||||||
const { L2VLAN, UNTAGGED } = NETWORK_TYPE;
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'HarvesterEditStorageNetwork',
|
name: 'HarvesterEditStorageNetwork',
|
||||||
@@ -60,14 +57,11 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
let parsedDefaultValue = {};
|
let parsedDefaultValue = {};
|
||||||
let openVlan = false;
|
let openVlan = false;
|
||||||
let networkType = L2VLAN;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
parsedDefaultValue = JSON.parse(this.value.value);
|
parsedDefaultValue = JSON.parse(this.value.value);
|
||||||
networkType = 'vlan' in parsedDefaultValue ? L2VLAN : UNTAGGED; // backend doesn't provide networkType, so we check if vlan is provided instead
|
|
||||||
openVlan = true;
|
openVlan = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
networkType = L2VLAN;
|
|
||||||
parsedDefaultValue = {
|
parsedDefaultValue = {
|
||||||
vlan: '',
|
vlan: '',
|
||||||
clusterNetwork: '',
|
clusterNetwork: '',
|
||||||
@@ -79,7 +73,6 @@ export default {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
openVlan,
|
openVlan,
|
||||||
networkType,
|
|
||||||
errors: [],
|
errors: [],
|
||||||
exclude,
|
exclude,
|
||||||
parsedDefaultValue,
|
parsedDefaultValue,
|
||||||
@@ -94,35 +87,16 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
showVlan() {
|
|
||||||
return this.networkType === L2VLAN;
|
|
||||||
},
|
|
||||||
networkTypes() {
|
|
||||||
const types = [L2VLAN];
|
|
||||||
|
|
||||||
if (this.untaggedNetworkSettingEnabled) {
|
|
||||||
types.push(UNTAGGED);
|
|
||||||
}
|
|
||||||
|
|
||||||
return types;
|
|
||||||
},
|
|
||||||
storageNetworkExampleLink() {
|
storageNetworkExampleLink() {
|
||||||
const version = this.$store.getters['harvester-common/getServerVersion']();
|
const version = this.$store.getters['harvester-common/getServerVersion']();
|
||||||
|
|
||||||
return docLink(DOC.STORAGE_NETWORK_EXAMPLE, version);
|
return docLink(DOC.STORAGE_NETWORK_EXAMPLE, version);
|
||||||
},
|
},
|
||||||
|
|
||||||
untaggedNetworkSettingEnabled() {
|
|
||||||
return this.$store.getters['harvester-common/getFeatureEnabled']('untaggedNetworkSetting');
|
|
||||||
},
|
|
||||||
|
|
||||||
clusterNetworkOptions() {
|
clusterNetworkOptions() {
|
||||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
const clusterNetworks = this.$store.getters[`${ inStore }/all`](HCI.CLUSTER_NETWORK) || [];
|
const clusterNetworks = this.$store.getters[`${ inStore }/all`](HCI.CLUSTER_NETWORK) || [];
|
||||||
// untaggedNetwork filter out mgmt cluster network
|
|
||||||
const clusterNetworksOptions = this.networkType === UNTAGGED ? clusterNetworks.filter((net) => net.id !== 'mgmt') : clusterNetworks;
|
|
||||||
|
|
||||||
return clusterNetworksOptions.map((n) => {
|
return clusterNetworks.map((n) => {
|
||||||
const disabled = !n.isReadyForStorageNetwork;
|
const disabled = !n.isReadyForStorageNetwork;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -134,50 +108,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
|
||||||
networkType: {
|
|
||||||
handler(neu) {
|
|
||||||
this.parsedDefaultValue.clusterNetwork = '';
|
|
||||||
|
|
||||||
if (neu === L2VLAN) {
|
|
||||||
this.parsedDefaultValue.vlan = '';
|
|
||||||
} else {
|
|
||||||
delete this.parsedDefaultValue.vlan;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deep: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
inputVlan(neu) {
|
|
||||||
if (neu === '') {
|
|
||||||
this.parsedDefaultValue.vlan = '';
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const newValue = Number(neu);
|
|
||||||
|
|
||||||
if (newValue > 4094) {
|
|
||||||
this.parsedDefaultValue.vlan = 4094;
|
|
||||||
} else if (newValue < 1) {
|
|
||||||
this.parsedDefaultValue.vlan = 1;
|
|
||||||
} else {
|
|
||||||
this.parsedDefaultValue.vlan = newValue;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
useDefault() {
|
|
||||||
this.openVlan = false;
|
|
||||||
this.networkType = L2VLAN;
|
|
||||||
this.parsedDefaultValue = {
|
|
||||||
vlan: '',
|
|
||||||
clusterNetwork: '',
|
|
||||||
range: '',
|
|
||||||
exclude: []
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
const exclude = this.exclude.filter((ip) => ip);
|
const exclude = this.exclude.filter((ip) => ip);
|
||||||
|
|
||||||
@@ -207,7 +138,7 @@ export default {
|
|||||||
errors.push(this.t('harvester.setting.storageNetwork.range.invalid', null, true));
|
errors.push(this.t('harvester.setting.storageNetwork.range.invalid', null, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.networkType === L2VLAN && !this.parsedDefaultValue.vlan) {
|
if (!this.parsedDefaultValue.vlan) {
|
||||||
errors.push(this.t('validation.required', { key: this.t('harvester.setting.storageNetwork.vlan') }, true));
|
errors.push(this.t('validation.required', { key: this.t('harvester.setting.storageNetwork.vlan') }, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,25 +191,13 @@ export default {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-if="openVlan">
|
<div v-if="openVlan">
|
||||||
<LabeledSelect
|
|
||||||
v-model:value="networkType"
|
|
||||||
class="mb-20"
|
|
||||||
:options="networkTypes"
|
|
||||||
:mode="mode"
|
|
||||||
:label="t('harvester.fields.type')"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
|
|
||||||
<LabeledInput
|
<LabeledInput
|
||||||
v-if="showVlan"
|
|
||||||
v-model:value.number="parsedDefaultValue.vlan"
|
v-model:value.number="parsedDefaultValue.vlan"
|
||||||
type="number"
|
type="number"
|
||||||
class="mb-20"
|
class="mb-20"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
required
|
required
|
||||||
placeholder="e.g. 1 - 4094"
|
|
||||||
label-key="harvester.setting.storageNetwork.vlan"
|
label-key="harvester.setting.storageNetwork.vlan"
|
||||||
@update:value="inputVlan"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<LabeledSelect
|
<LabeledSelect
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export default {
|
|||||||
name="model"
|
name="model"
|
||||||
:options="[true,false]"
|
:options="[true,false]"
|
||||||
:labels="[t('generic.enabled'), t('generic.disabled')]"
|
:labels="[t('generic.enabled'), t('generic.disabled')]"
|
||||||
@input="update"
|
@update:value="update"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<LabeledInput
|
<LabeledInput
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const featuresV133 = [
|
|||||||
|
|
||||||
// https://github.com/harvester/dashboard/releases/tag/v1.4.0
|
// https://github.com/harvester/dashboard/releases/tag/v1.4.0
|
||||||
const featuresV140 = [
|
const featuresV140 = [
|
||||||
...featuresV133,
|
...featuresV132,
|
||||||
'cpuPinning',
|
'cpuPinning',
|
||||||
'usbPassthrough',
|
'usbPassthrough',
|
||||||
'volumeEncryption',
|
'volumeEncryption',
|
||||||
@@ -40,18 +40,21 @@ const featuresV141 = [
|
|||||||
...featuresV140
|
...featuresV140
|
||||||
];
|
];
|
||||||
|
|
||||||
// TODO: add v1.4.2 official release note
|
// https://github.com/harvester/dashboard/releases/tag/v1.4.2
|
||||||
const featuresV142 = [
|
const featuresV142 = [
|
||||||
...featuresV141
|
...featuresV141,
|
||||||
|
'refreshIntervalInSecond',
|
||||||
|
'allowEmptySnapshotClassName'
|
||||||
];
|
];
|
||||||
|
|
||||||
// TODO: add v1.5.0 official release note
|
// https://github.com/harvester/dashboard/releases/tag/v1.4.3-rc1
|
||||||
const featuresV150 = [
|
const featuresV143 = [
|
||||||
...featuresV142,
|
...featuresV142,
|
||||||
'tpmPersistentState',
|
];
|
||||||
'efiPersistentState',
|
|
||||||
'untaggedNetworkSetting',
|
// https://github.com/harvester/harvester-ui-extension/releases/tag/v1.5.0
|
||||||
'skipSingleReplicaDetachedVol'
|
const featuresV150 = [
|
||||||
|
...featuresV142
|
||||||
];
|
];
|
||||||
|
|
||||||
export const RELEASE_FEATURES = {
|
export const RELEASE_FEATURES = {
|
||||||
@@ -62,5 +65,6 @@ export const RELEASE_FEATURES = {
|
|||||||
'v1.4.0': featuresV140,
|
'v1.4.0': featuresV140,
|
||||||
'v1.4.1': featuresV141,
|
'v1.4.1': featuresV141,
|
||||||
'v1.4.2': featuresV142,
|
'v1.4.2': featuresV142,
|
||||||
|
'v1.4.3': featuresV143,
|
||||||
'v1.5.0': featuresV150
|
'v1.5.0': featuresV150
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,61 +7,60 @@ export const LABELS_TO_IGNORE_REGEX = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const HCI = {
|
export const HCI = {
|
||||||
CLOUD_INIT: 'harvesterhci.io/cloud-init-template',
|
CLOUD_INIT: 'harvesterhci.io/cloud-init-template',
|
||||||
CURRENT_IP: 'rke2.io/internal-ip',
|
CURRENT_IP: 'rke2.io/internal-ip',
|
||||||
IMAGE_ID: 'harvesterhci.io/imageId',
|
IMAGE_ID: 'harvesterhci.io/imageId',
|
||||||
SSH_NAMES: 'harvesterhci.io/sshNames',
|
SSH_NAMES: 'harvesterhci.io/sshNames',
|
||||||
NETWORK_IPS: 'network.harvesterhci.io/ips',
|
NETWORK_IPS: 'network.harvesterhci.io/ips',
|
||||||
TEMPLATE_VERSION_CUSTOM_NAME: 'template-version.harvesterhci.io/customName',
|
TEMPLATE_VERSION_CUSTOM_NAME: 'template-version.harvesterhci.io/customName',
|
||||||
CREATOR: 'harvesterhci.io/creator',
|
CREATOR: 'harvesterhci.io/creator',
|
||||||
OS: 'harvesterhci.io/os',
|
OS: 'harvesterhci.io/os',
|
||||||
NETWORK_TYPE: 'network.harvesterhci.io/type',
|
NETWORK_TYPE: 'network.harvesterhci.io/type',
|
||||||
VM_NAME: 'harvesterhci.io/vmName',
|
VM_NAME: 'harvesterhci.io/vmName',
|
||||||
VM_NAME_PREFIX: 'harvesterhci.io/vmNamePrefix',
|
VM_NAME_PREFIX: 'harvesterhci.io/vmNamePrefix',
|
||||||
VM_RESERVED_MEMORY: 'harvesterhci.io/reservedMemory',
|
VM_RESERVED_MEMORY: 'harvesterhci.io/reservedMemory',
|
||||||
MAINTENANCE_STATUS: 'harvesterhci.io/maintain-status',
|
MAINTENANCE_STATUS: 'harvesterhci.io/maintain-status',
|
||||||
HOST_CUSTOM_NAME: 'harvesterhci.io/host-custom-name',
|
HOST_CUSTOM_NAME: 'harvesterhci.io/host-custom-name',
|
||||||
HOST_CONSOLE_URL: 'harvesterhci.io/host-console-url',
|
HOST_CONSOLE_URL: 'harvesterhci.io/host-console-url',
|
||||||
RESTORE_NAME: 'restore.harvesterhci.io/name',
|
RESTORE_NAME: 'restore.harvesterhci.io/name',
|
||||||
NODE_ROLE_MASTER: 'node-role.kubernetes.io/master',
|
NODE_ROLE_MASTER: 'node-role.kubernetes.io/master',
|
||||||
NODE_ROLE_CONTROL_PLANE: 'node-role.kubernetes.io/control-plane',
|
NODE_ROLE_CONTROL_PLANE: 'node-role.kubernetes.io/control-plane',
|
||||||
NODE_ROLE_ETCD: 'node-role.harvesterhci.io/witness',
|
NODE_ROLE_ETCD: 'node-role.harvesterhci.io/witness',
|
||||||
PROMOTE_STATUS: 'harvesterhci.io/promote-status',
|
PROMOTE_STATUS: 'harvesterhci.io/promote-status',
|
||||||
MIGRATION_STATE: 'harvesterhci.io/migrationState',
|
MIGRATION_STATE: 'harvesterhci.io/migrationState',
|
||||||
VOLUME_CLAIM_TEMPLATE: 'harvesterhci.io/volumeClaimTemplates',
|
VOLUME_CLAIM_TEMPLATE: 'harvesterhci.io/volumeClaimTemplates',
|
||||||
IMAGE_NAME: 'harvesterhci.io/image-name',
|
IMAGE_NAME: 'harvesterhci.io/image-name',
|
||||||
INIT_IP: 'etcd.rke2.cattle.io/node-address',
|
INIT_IP: 'etcd.rke2.cattle.io/node-address',
|
||||||
NODE_SCHEDULABLE: 'kubevirt.io/schedulable',
|
NODE_SCHEDULABLE: 'kubevirt.io/schedulable',
|
||||||
NETWORK_ROUTE: 'network.harvesterhci.io/route',
|
NETWORK_ROUTE: 'network.harvesterhci.io/route',
|
||||||
MATCHED_NODES: 'network.harvesterhci.io/matched-nodes',
|
MATCHED_NODES: 'network.harvesterhci.io/matched-nodes',
|
||||||
OS_UPGRADE_IMAGE: 'harvesterhci.io/os-upgrade-image',
|
OS_UPGRADE_IMAGE: 'harvesterhci.io/os-upgrade-image',
|
||||||
LATEST_UPGRADE: 'harvesterhci.io/latestUpgrade',
|
LATEST_UPGRADE: 'harvesterhci.io/latestUpgrade',
|
||||||
UPGRADE_STATE: 'harvesterhci.io/upgradeState',
|
UPGRADE_STATE: 'harvesterhci.io/upgradeState',
|
||||||
REAY_MESSAGE: 'harvesterhci.io/read-message',
|
REAY_MESSAGE: 'harvesterhci.io/read-message',
|
||||||
DYNAMIC_SSHKEYS_NAMES: 'harvesterhci.io/dynamic-ssh-key-names',
|
DYNAMIC_SSHKEYS_NAMES: 'harvesterhci.io/dynamic-ssh-key-names',
|
||||||
DYNAMIC_SSHKEYS_USERS: 'harvesterhci.io/dynamic-ssh-key-users',
|
DYNAMIC_SSHKEYS_USERS: 'harvesterhci.io/dynamic-ssh-key-users',
|
||||||
IMAGE_SUFFIX: 'harvesterhci.io/image-type',
|
IMAGE_SUFFIX: 'harvesterhci.io/image-type',
|
||||||
OS_TYPE: 'harvesterhci.io/os-type',
|
OS_TYPE: 'harvesterhci.io/os-type',
|
||||||
STORAGE_PROVISIONER: 'harvesterhci.io/storageProvisioner',
|
STORAGE_PROVISIONER: 'harvesterhci.io/storageProvisioner',
|
||||||
SKIP_SINGLE_REPLICA_DETACHED_VOL: 'harvesterhci.io/skipSingleReplicaDetachedVol',
|
HOST_REQUEST: 'management.cattle.io/pod-requests',
|
||||||
HOST_REQUEST: 'management.cattle.io/pod-requests',
|
STORAGE_CLASS: 'harvesterhci.io/storageClassName',
|
||||||
STORAGE_CLASS: 'harvesterhci.io/storageClassName',
|
STORAGE_NETWORK: 'storage-network.settings.harvesterhci.io',
|
||||||
STORAGE_NETWORK: 'storage-network.settings.harvesterhci.io',
|
ADDON_EXPERIMENTAL: 'addon.harvesterhci.io/experimental',
|
||||||
ADDON_EXPERIMENTAL: 'addon.harvesterhci.io/experimental',
|
VOLUME_ERROR: 'longhorn.io/volume-scheduling-error',
|
||||||
VOLUME_ERROR: 'longhorn.io/volume-scheduling-error',
|
KVM_AMD_CPU: 'cpu-feature.node.kubevirt.io/svm',
|
||||||
KVM_AMD_CPU: 'cpu-feature.node.kubevirt.io/svm',
|
KVM_INTEL_CPU: 'cpu-feature.node.kubevirt.io/vmx',
|
||||||
KVM_INTEL_CPU: 'cpu-feature.node.kubevirt.io/vmx',
|
NODE_MANUFACTURER: 'manufacturer',
|
||||||
NODE_MANUFACTURER: 'manufacturer',
|
NODE_MODEL: 'model',
|
||||||
NODE_MODEL: 'model',
|
NODE_SERIAL_NUMBER: 'serialNumber',
|
||||||
NODE_SERIAL_NUMBER: 'serialNumber',
|
VM_INSUFFICIENT: 'harvesterhci.io/insufficient-resource-quota',
|
||||||
VM_INSUFFICIENT: 'harvesterhci.io/insufficient-resource-quota',
|
NODE_NTP_SYNC_STATUS: 'node.harvesterhci.io/ntp-service',
|
||||||
NODE_NTP_SYNC_STATUS: 'node.harvesterhci.io/ntp-service',
|
PARENT_SRIOV: 'harvesterhci.io/parent-sriov-network-device',
|
||||||
PARENT_SRIOV: 'harvesterhci.io/parent-sriov-network-device',
|
PARENT_SRIOV_GPU: 'harvesterhci.io/parentSRIOVGPUDevice',
|
||||||
PARENT_SRIOV_GPU: 'harvesterhci.io/parentSRIOVGPUDevice',
|
VM_MAINTENANCE_MODE_STRATEGY: 'harvesterhci.io/maintain-mode-strategy',
|
||||||
VM_MAINTENANCE_MODE_STRATEGY: 'harvesterhci.io/maintain-mode-strategy',
|
NODE_CPU_MANAGER_UPDATE_STATUS: 'harvesterhci.io/cpu-manager-update-status',
|
||||||
NODE_CPU_MANAGER_UPDATE_STATUS: 'harvesterhci.io/cpu-manager-update-status',
|
CPU_MANAGER: 'cpumanager',
|
||||||
CPU_MANAGER: 'cpumanager',
|
VM_DEVICE_ALLOCATION_DETAILS: 'harvesterhci.io/deviceAllocationDetails',
|
||||||
VM_DEVICE_ALLOCATION_DETAILS: 'harvesterhci.io/deviceAllocationDetails',
|
SVM_BACKUP_ID: 'harvesterhci.io/svmbackupId',
|
||||||
SVM_BACKUP_ID: 'harvesterhci.io/svmbackupId',
|
DISABLE_LONGHORN_V2_ENGINE: 'node.longhorn.io/disable-v2-data-engine',
|
||||||
DISABLE_LONGHORN_V2_ENGINE: 'node.longhorn.io/disable-v2-data-engine',
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -65,9 +65,7 @@ export const HCI_ALLOWED_SETTINGS = {
|
|||||||
[HCI_SETTING.SUPPORT_BUNDLE_EXPIRATION]: {},
|
[HCI_SETTING.SUPPORT_BUNDLE_EXPIRATION]: {},
|
||||||
[HCI_SETTING.SUPPORT_BUNDLE_NODE_COLLECTION_TIMEOUT]: { featureFlag: 'supportBundleNodeCollectionTimeoutSetting' },
|
[HCI_SETTING.SUPPORT_BUNDLE_NODE_COLLECTION_TIMEOUT]: { featureFlag: 'supportBundleNodeCollectionTimeoutSetting' },
|
||||||
[HCI_SETTING.SUPPORT_BUNDLE_IMAGE]: { kind: 'json', from: 'import' },
|
[HCI_SETTING.SUPPORT_BUNDLE_IMAGE]: { kind: 'json', from: 'import' },
|
||||||
[HCI_SETTING.STORAGE_NETWORK]: {
|
[HCI_SETTING.STORAGE_NETWORK]: { kind: 'custom', from: 'import' },
|
||||||
kind: 'custom', from: 'import', canReset: true
|
|
||||||
},
|
|
||||||
[HCI_SETTING.VM_FORCE_RESET_POLICY]: { kind: 'json', from: 'import' },
|
[HCI_SETTING.VM_FORCE_RESET_POLICY]: { kind: 'json', from: 'import' },
|
||||||
[HCI_SETTING.SSL_CERTIFICATES]: { kind: 'json', from: 'import' },
|
[HCI_SETTING.SSL_CERTIFICATES]: { kind: 'json', from: 'import' },
|
||||||
[HCI_SETTING.SSL_PARAMETERS]: {
|
[HCI_SETTING.SSL_PARAMETERS]: {
|
||||||
|
|||||||
@@ -2,8 +2,3 @@ export const BACKUP_TYPE = {
|
|||||||
BACKUP: 'backup',
|
BACKUP: 'backup',
|
||||||
SNAPSHOT: 'snapshot'
|
SNAPSHOT: 'snapshot'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NETWORK_TYPE = {
|
|
||||||
L2VLAN: 'L2VlanNetwork',
|
|
||||||
UNTAGGED: 'UntaggedNetwork'
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,173 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { mapState } from 'vuex';
|
|
||||||
import { exceptionToErrorsArray } from '@shell/utils/error';
|
|
||||||
import { alternateLabel } from '@shell/utils/platform';
|
|
||||||
import AsyncButton from '@shell/components/AsyncButton';
|
|
||||||
import { Banner } from '@components/Banner';
|
|
||||||
import { Card } from '@components/Card';
|
|
||||||
import { escapeHtml } from '@shell/utils/string';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name ConfirmExecutionDialog
|
|
||||||
* @description Dialog component to confirm the related resources before executing the action.
|
|
||||||
*/
|
|
||||||
export default {
|
|
||||||
name: 'ConfirmExecutionDialog',
|
|
||||||
|
|
||||||
emits: ['close'],
|
|
||||||
|
|
||||||
components: {
|
|
||||||
AsyncButton,
|
|
||||||
Banner,
|
|
||||||
Card,
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
/**
|
|
||||||
* @property resources to be deleted.
|
|
||||||
* @type {Resource[]} Array of the resource model's instance
|
|
||||||
*/
|
|
||||||
resources: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return { errors: [] };
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
...mapState('action-menu', ['modalData']),
|
|
||||||
|
|
||||||
warningMessageKey() {
|
|
||||||
return this.modalData.warningMessageKey;
|
|
||||||
},
|
|
||||||
|
|
||||||
names() {
|
|
||||||
return this.resources.map((obj) => obj.nameDisplay).slice(0, 5);
|
|
||||||
},
|
|
||||||
|
|
||||||
resourceNames() {
|
|
||||||
return this.names.reduce((res, name, i) => {
|
|
||||||
if (i >= 5) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
res += `<b>${ escapeHtml(name) }</b>`;
|
|
||||||
if (i === this.names.length - 1) {
|
|
||||||
res += this.plusMore;
|
|
||||||
} else {
|
|
||||||
res += i === this.resources.length - 2 ? ' and ' : ', ';
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}, '');
|
|
||||||
},
|
|
||||||
|
|
||||||
plusMore() {
|
|
||||||
const remaining = this.resources.length - this.names.length;
|
|
||||||
|
|
||||||
return this.t('dialog.confirmExecution.andOthers', { count: remaining });
|
|
||||||
},
|
|
||||||
|
|
||||||
type() {
|
|
||||||
const types = new Set(this.resources.reduce((array, each) => {
|
|
||||||
array.push(each.type);
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}, []));
|
|
||||||
|
|
||||||
if (types.size > 1) {
|
|
||||||
return this.t('generic.resource', { count: this.resources.length });
|
|
||||||
}
|
|
||||||
|
|
||||||
const schema = this.resources[0]?.schema;
|
|
||||||
|
|
||||||
if ( !schema ) {
|
|
||||||
return `resource${ this.resources.length === 1 ? '' : 's' }`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.$store.getters['type-map/labelFor'](schema, this.resources.length);
|
|
||||||
},
|
|
||||||
|
|
||||||
protip() {
|
|
||||||
return this.t('dialog.confirmExecution.protip', { alternateLabel });
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
escapeHtml,
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this.errors = [];
|
|
||||||
this.$emit('close');
|
|
||||||
},
|
|
||||||
|
|
||||||
async apply(buttonDone) {
|
|
||||||
try {
|
|
||||||
for (const resource of this.resources) {
|
|
||||||
await resource.doActionGrowl(this.modalData.action, {});
|
|
||||||
}
|
|
||||||
buttonDone(true);
|
|
||||||
this.close();
|
|
||||||
} catch (e) {
|
|
||||||
this.errors = exceptionToErrorsArray(e);
|
|
||||||
buttonDone(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Card :show-highlight-border="false">
|
|
||||||
<template #title>
|
|
||||||
<h4 class="text-default-text">
|
|
||||||
{{ t('dialog.confirmExecution.title') }}
|
|
||||||
</h4>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #body>
|
|
||||||
<div class="pl-10 pr-10">
|
|
||||||
<span
|
|
||||||
v-clean-html="t(warningMessageKey, { type, names: resourceNames }, true)"
|
|
||||||
></span>
|
|
||||||
<div class="text-info mt-20">
|
|
||||||
{{ protip }}
|
|
||||||
</div>
|
|
||||||
<Banner
|
|
||||||
v-for="(error, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #actions>
|
|
||||||
<div class="actions">
|
|
||||||
<button
|
|
||||||
class="btn role-secondary"
|
|
||||||
@click="close"
|
|
||||||
>
|
|
||||||
{{ t('generic.cancel') }}
|
|
||||||
</button>
|
|
||||||
<AsyncButton
|
|
||||||
mode="apply"
|
|
||||||
class="btn bg-primary ml-10"
|
|
||||||
:disabled="applyDisabled"
|
|
||||||
@click="apply"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</Card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
|
||||||
.modal-container {
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
width: 100%;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -166,6 +166,8 @@ export default {
|
|||||||
<Banner
|
<Banner
|
||||||
v-for="(error, i) in errors"
|
v-for="(error, i) in errors"
|
||||||
:key="i"
|
:key="i"
|
||||||
|
:label="error"
|
||||||
|
color="error"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -106,6 +106,12 @@ export default {
|
|||||||
:label="t('harvester.modal.cloneVM.name')"
|
:label="t('harvester.modal.cloneVM.name')"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
:label="err"
|
||||||
|
color="error"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -125,13 +131,6 @@ export default {
|
|||||||
@click="create"
|
@click="create"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
color="error"
|
|
||||||
:label="err"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -137,6 +137,12 @@ export default {
|
|||||||
class="mt-20"
|
class="mt-20"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
:label="err"
|
||||||
|
color="error"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -156,11 +162,6 @@ export default {
|
|||||||
@click="save"
|
@click="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -103,6 +103,12 @@ export default {
|
|||||||
:label="t('generic.name')"
|
:label="t('generic.name')"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -121,13 +127,6 @@ export default {
|
|||||||
@click="save"
|
@click="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
color="error"
|
|
||||||
:label="err"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -120,6 +120,12 @@ export default {
|
|||||||
v-model:value="description"
|
v-model:value="description"
|
||||||
:label="t('harvester.modal.createTemplate.description')"
|
:label="t('harvester.modal.createTemplate.description')"
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -138,11 +144,6 @@ export default {
|
|||||||
@click="save"
|
@click="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -128,6 +128,12 @@ export default {
|
|||||||
<Banner color="warning">
|
<Banner color="warning">
|
||||||
<span>{{ t('harvester.modal.ejectCDROM.warnTip') }}</span>
|
<span>{{ t('harvester.modal.ejectCDROM.warnTip') }}</span>
|
||||||
</Banner>
|
</Banner>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -147,13 +153,6 @@ export default {
|
|||||||
@click="remove"
|
@click="remove"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
color="error"
|
|
||||||
:label="err"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -164,6 +164,12 @@ export default {
|
|||||||
class="mt-20"
|
class="mt-20"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -182,11 +188,6 @@ export default {
|
|||||||
@click="save"
|
@click="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -161,6 +161,12 @@ export default {
|
|||||||
:placeholder="t('harvester.modal.migration.fields.nodeName.placeholder')"
|
:placeholder="t('harvester.modal.migration.fields.nodeName.placeholder')"
|
||||||
:options="nodeNameList"
|
:options="nodeNameList"
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template
|
<template
|
||||||
@@ -181,12 +187,6 @@ export default {
|
|||||||
@click="apply"
|
@click="apply"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
color="error"
|
|
||||||
:label="err"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ export default {
|
|||||||
suffix="GiB"
|
suffix="GiB"
|
||||||
class="mb-20"
|
class="mb-20"
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -108,12 +114,6 @@ export default {
|
|||||||
</button>
|
</button>
|
||||||
<AsyncButton @click="save" />
|
<AsyncButton @click="save" />
|
||||||
</div>
|
</div>
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
color="error"
|
|
||||||
:label="err"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -136,6 +136,12 @@ export default {
|
|||||||
:options="backupOption"
|
:options="backupOption"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -154,11 +160,6 @@ export default {
|
|||||||
@click="saveRestore"
|
@click="saveRestore"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -90,6 +90,12 @@ export default {
|
|||||||
v-clean-html="t('harvester.virtualMachine.unplug.title', { name: diskName })"
|
v-clean-html="t('harvester.virtualMachine.unplug.title', { name: diskName })"
|
||||||
class="text-default-text"
|
class="text-default-text"
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -111,13 +117,6 @@ export default {
|
|||||||
@click="save"
|
@click="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
color="error"
|
|
||||||
:label="err"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -132,6 +132,12 @@ export default {
|
|||||||
:label="t('generic.name')"
|
:label="t('generic.name')"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -150,11 +156,6 @@ export default {
|
|||||||
@click="save"
|
@click="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ export default {
|
|||||||
:placeholder="t('harvester.harvesterVlanConfigMigrateDialog.targetClusterNetwork.placeholder')"
|
:placeholder="t('harvester.harvesterVlanConfigMigrateDialog.targetClusterNetwork.placeholder')"
|
||||||
:options="clusterNetworks"
|
:options="clusterNetworks"
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -125,11 +131,6 @@ export default {
|
|||||||
@click="apply"
|
@click="apply"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -70,16 +70,16 @@ export default {
|
|||||||
v-clean-html="t('harvester.modal.restart.tip')"
|
v-clean-html="t('harvester.modal.restart.tip')"
|
||||||
class="pl-10 pr-10"
|
class="pl-10 pr-10"
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
color="error"
|
|
||||||
:label="err"
|
|
||||||
/>
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button
|
<button
|
||||||
class="btn role-secondary mr-10"
|
class="btn role-secondary mr-10"
|
||||||
|
|||||||
@@ -145,6 +145,12 @@ export default {
|
|||||||
class="mt-20"
|
class="mt-20"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -162,10 +168,6 @@ export default {
|
|||||||
@click="save"
|
@click="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -79,6 +79,12 @@ export default {
|
|||||||
:label="t('harvester.modal.snapshot.name')"
|
:label="t('harvester.modal.snapshot.name')"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -96,12 +102,6 @@ export default {
|
|||||||
@click="save"
|
@click="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
color="error"
|
|
||||||
:label="err"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -98,6 +98,12 @@ export default {
|
|||||||
:label="t('harvester.modal.volumeClone.name')"
|
:label="t('harvester.modal.volumeClone.name')"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<Banner
|
||||||
|
v-for="(err, i) in errors"
|
||||||
|
:key="i"
|
||||||
|
color="error"
|
||||||
|
:label="err"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
@@ -115,10 +121,6 @@ export default {
|
|||||||
@click="save"
|
@click="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Banner
|
|
||||||
v-for="(err, i) in errors"
|
|
||||||
:key="i"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { Banner } from '@components/Banner';
|
|||||||
|
|
||||||
import CreateEditView from '@shell/mixins/create-edit-view';
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||||
|
|
||||||
const DEFAULT_VALUE = { image: { repo: 'rancher/harvester-nvidia-driver-toolkit' } };
|
const DEFAULT_VALUE = { image: { repository: 'rancher/harvester-nvidia-driver-toolkit' } };
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'EditAddonNvidiaDriverToolkit',
|
name: 'EditAddonNvidiaDriverToolkit',
|
||||||
@@ -122,7 +122,7 @@ export default {
|
|||||||
>
|
>
|
||||||
<div class="col span-6">
|
<div class="col span-6">
|
||||||
<LabeledInput
|
<LabeledInput
|
||||||
v-model:value="valuesContentJson.image.repo"
|
v-model:value="valuesContentJson.image.repository"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
:required="true"
|
:required="true"
|
||||||
label-key="harvester.addons.nvidiaDriverToolkit.image.repository"
|
label-key="harvester.addons.nvidiaDriverToolkit.image.repository"
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ import { HCI as HCI_LABELS_ANNOTATIONS } from '@pkg/harvester/config/labels-anno
|
|||||||
import CreateEditView from '@shell/mixins/create-edit-view';
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
||||||
import { allHash } from '@shell/utils/promise';
|
import { allHash } from '@shell/utils/promise';
|
||||||
import { HCI } from '../types';
|
import { HCI } from '../types';
|
||||||
import { NETWORK_TYPE } from '../config/types';
|
|
||||||
|
|
||||||
const { L2VLAN, UNTAGGED } = NETWORK_TYPE;
|
|
||||||
|
|
||||||
const AUTO = 'auto';
|
const AUTO = 'auto';
|
||||||
const MANUAL = 'manual';
|
const MANUAL = 'manual';
|
||||||
@@ -51,7 +48,7 @@ export default {
|
|||||||
config.bridge = config.bridge.slice(0, -3);
|
config.bridge = config.bridge.slice(0, -3);
|
||||||
}
|
}
|
||||||
|
|
||||||
const type = this.value.vlanType || L2VLAN ;
|
const type = this.value.vlanType || 'L2VlanNetwork' ;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
config,
|
config,
|
||||||
@@ -104,15 +101,15 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
networkType() {
|
networkType() {
|
||||||
return [L2VLAN, UNTAGGED];
|
return ['L2VlanNetwork', 'UntaggedNetwork'];
|
||||||
},
|
},
|
||||||
|
|
||||||
isUntaggedNetwork() {
|
isUntaggedNetwork() {
|
||||||
if (this.isView) {
|
if (this.isView) {
|
||||||
return this.value.vlanType === UNTAGGED;
|
return this.value.vlanType === 'UntaggedNetwork';
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.type === UNTAGGED;
|
return this.type === 'UntaggedNetwork';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ export default {
|
|||||||
:disabled="isEdit || isView"
|
:disabled="isEdit || isView"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
row
|
row
|
||||||
@input="onTypeChange"
|
@update:value="onTypeChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-30">
|
<div class="row mb-30">
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ const CLONE = 'clone';
|
|||||||
const DOWNLOAD = 'download';
|
const DOWNLOAD = 'download';
|
||||||
const UPLOAD = 'upload';
|
const UPLOAD = 'upload';
|
||||||
const rawORqcow2 = 'raw_qcow2';
|
const rawORqcow2 = 'raw_qcow2';
|
||||||
const LONGHORN = 'longhorn';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'EditImage',
|
name: 'EditImage',
|
||||||
@@ -61,7 +60,10 @@ export default {
|
|||||||
images: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.IMAGE }),
|
images: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.IMAGE }),
|
||||||
storageClasses: this.$store.dispatch(`${ inStore }/findAll`, { type: STORAGE_CLASS }),
|
storageClasses: this.$store.dispatch(`${ inStore }/findAll`, { type: STORAGE_CLASS }),
|
||||||
});
|
});
|
||||||
this['storageClassName'] = this.storageClassName || this.defaultStorageClassName();
|
|
||||||
|
const defaultStorage = this.$store.getters[`${ inStore }/all`](STORAGE_CLASS).find((s) => s.isDefault);
|
||||||
|
|
||||||
|
this['storageClassName'] = this.storageClassName || defaultStorage?.metadata?.name || 'longhorn';
|
||||||
this.images = this.$store.getters[`${ inStore }/all`](HCI.IMAGE);
|
this.images = this.$store.getters[`${ inStore }/all`](HCI.IMAGE);
|
||||||
|
|
||||||
const { securityParameters } = this.value.spec;
|
const { securityParameters } = this.value.spec;
|
||||||
@@ -142,22 +144,9 @@ export default {
|
|||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
encryptedStorageClasses() {
|
|
||||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
||||||
const storages = this.$store.getters[`${ inStore }/all`](STORAGE_CLASS);
|
|
||||||
|
|
||||||
return storages.filter((s) => s.isEncrypted);
|
|
||||||
},
|
|
||||||
|
|
||||||
nonEncryptedStorageClasses() {
|
|
||||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
||||||
const storages = this.$store.getters[`${ inStore }/all`](STORAGE_CLASS);
|
|
||||||
|
|
||||||
return storages.filter((s) => !s.isEncrypted);
|
|
||||||
},
|
|
||||||
|
|
||||||
storageClassOptions() {
|
storageClassOptions() {
|
||||||
const storages = this.value.spec?.securityParameters?.cryptoOperation === ENCRYPT ? this.encryptedStorageClasses : this.nonEncryptedStorageClasses;
|
const inStore = this.$store.getters['currentProduct'].inStore;
|
||||||
|
const storages = this.$store.getters[`${ inStore }/all`](STORAGE_CLASS);
|
||||||
|
|
||||||
return storages
|
return storages
|
||||||
.filter((s) => !s.parameters?.backingImage && s.provisioner !== LVM_DRIVER) // Lvm storage is not supported.
|
.filter((s) => !s.parameters?.backingImage && s.provisioner !== LVM_DRIVER) // Lvm storage is not supported.
|
||||||
@@ -250,13 +239,6 @@ export default {
|
|||||||
this.$refs.file.value = null;
|
this.$refs.file.value = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'value.spec.securityParameters.cryptoOperation'() {
|
|
||||||
if (this.value.spec?.securityParameters?.cryptoOperation === ENCRYPT) {
|
|
||||||
this.storageClassName = this.encryptedStorageClasses[0]?.name || '';
|
|
||||||
} else { // URL / FILE / DECRYPT should use default storage class
|
|
||||||
this.storageClassName = this.defaultStorageClassName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -403,18 +385,6 @@ export default {
|
|||||||
return str.toLowerCase().includes(os.value.toLowerCase()) ? os.value : false;
|
return str.toLowerCase().includes(os.value.toLowerCase()) ? os.value : false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
defaultStorageClassName() {
|
|
||||||
const inStore = this.$store.getters['currentProduct'].inStore;
|
|
||||||
const defaultStorage = this.$store.getters[`${ inStore }/all`](STORAGE_CLASS).find((s) => s.isDefault);
|
|
||||||
|
|
||||||
if (!defaultStorage) {
|
|
||||||
return LONGHORN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if default sc is encrypted, use longhorn as default
|
|
||||||
return defaultStorage.isEncrypted ? LONGHORN : defaultStorage?.metadata?.name;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -434,7 +434,7 @@ export default {
|
|||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
v-if="value.cpuPinningFeatureEnabled"
|
v-if="value.cpuPinningFeatureEnabled"
|
||||||
v-model:value="cpuPinning"
|
v-model="cpuPinning"
|
||||||
class="check"
|
class="check"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
tooltip-key="harvester.virtualMachine.cpuPinning.tooltip"
|
tooltip-key="harvester.virtualMachine.cpuPinning.tooltip"
|
||||||
@@ -465,29 +465,11 @@ export default {
|
|||||||
:mode="mode"
|
:mode="mode"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Checkbox
|
|
||||||
v-if="value.tpmPersistentStateFeatureEnabled && tpmEnabled"
|
|
||||||
v-model:value="tpmPersistentStateEnabled"
|
|
||||||
class="check"
|
|
||||||
type="checkbox"
|
|
||||||
:label="t('harvester.virtualMachine.advancedOptions.tpmPersistentState')"
|
|
||||||
:mode="mode"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
v-model:value="efiEnabled"
|
v-model:value="efiEnabled"
|
||||||
class="check"
|
class="check"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:label="t('harvester.virtualMachine.advancedOptions.efiEnabled')"
|
:label="t('harvester.virtualMachine.efiEnabled')"
|
||||||
:mode="mode"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Checkbox
|
|
||||||
v-if="value.efiPersistentStateFeatureEnabled && efiEnabled"
|
|
||||||
v-model:value="efiPersistentStateEnabled"
|
|
||||||
class="check"
|
|
||||||
type="checkbox"
|
|
||||||
:label="t('harvester.virtualMachine.advancedOptions.efiPersistentState')"
|
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -496,7 +478,7 @@ export default {
|
|||||||
v-model:value="secureBoot"
|
v-model:value="secureBoot"
|
||||||
class="check"
|
class="check"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:label="t('harvester.virtualMachine.advancedOptions.secureBoot')"
|
:label="t('harvester.virtualMachine.secureBoot')"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { randomStr } from '@shell/utils/string';
|
import { randomStr } from '@shell/utils/string';
|
||||||
|
import { clone } from '@shell/utils/object';
|
||||||
import { LabeledInput } from '@components/Form/LabeledInput';
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
||||||
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
||||||
import ModalWithCard from '@shell/components/ModalWithCard';
|
import ModalWithCard from '@shell/components/ModalWithCard';
|
||||||
|
|
||||||
import { clone } from '@shell/utils/object';
|
|
||||||
import { _VIEW } from '@shell/config/query-params';
|
import { _VIEW } from '@shell/config/query-params';
|
||||||
|
|
||||||
import { NAMESPACE } from '@shell/config/types';
|
import { NAMESPACE } from '@shell/config/types';
|
||||||
import { HCI } from '../../types';
|
import { HCI } from '../../types';
|
||||||
|
|
||||||
@@ -126,10 +123,10 @@ export default {
|
|||||||
this.checkedSsh = neu;
|
this.checkedSsh = neu;
|
||||||
},
|
},
|
||||||
|
|
||||||
checkedSsh(val, old) {
|
checkedSsh(val) {
|
||||||
if ( val.includes(_NEW)) {
|
// if click on Create a New...
|
||||||
this['checkedSsh'] = old;
|
if (val.includes(_NEW)) {
|
||||||
this.update();
|
this.checkedSsh = this.checkedSsh.filter((key) => key !== _NEW);
|
||||||
this.show();
|
this.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,6 +172,7 @@ export default {
|
|||||||
|
|
||||||
if (res.id) {
|
if (res.id) {
|
||||||
this.checkedSsh.push(`${ this.namespace }/${ this.sshName }`);
|
this.checkedSsh.push(`${ this.namespace }/${ this.sshName }`);
|
||||||
|
this.update();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -243,13 +241,13 @@ export default {
|
|||||||
<LabeledSelect
|
<LabeledSelect
|
||||||
v-model:value="checkedSsh"
|
v-model:value="checkedSsh"
|
||||||
:label="t('harvester.virtualMachine.input.sshKey')"
|
:label="t('harvester.virtualMachine.input.sshKey')"
|
||||||
:taggable="true"
|
:taggable="!disabled"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
:searchable="searchable"
|
:searchable="searchable"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:options="sshOption"
|
:options="sshOption"
|
||||||
@input="update"
|
@update:value="update"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ModalWithCard
|
<ModalWithCard
|
||||||
|
|||||||
@@ -579,7 +579,7 @@ export default {
|
|||||||
:create-namespace="true"
|
:create-namespace="true"
|
||||||
:namespace="value.metadata.namespace"
|
:namespace="value.metadata.namespace"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
:disabled="isWindows"
|
:disabled="isWindows || isEdit"
|
||||||
@update:sshKey="updateSSHKey"
|
@update:sshKey="updateSSHKey"
|
||||||
@register-after-hook="registerAfterHook"
|
@register-after-hook="registerAfterHook"
|
||||||
/>
|
/>
|
||||||
@@ -873,29 +873,11 @@ export default {
|
|||||||
:mode="mode"
|
:mode="mode"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Checkbox
|
|
||||||
v-if="value.tpmPersistentStateFeatureEnabled && tpmEnabled"
|
|
||||||
v-model:value="tpmPersistentStateEnabled"
|
|
||||||
class="check"
|
|
||||||
type="checkbox"
|
|
||||||
:label="t('harvester.virtualMachine.advancedOptions.tpmPersistentState')"
|
|
||||||
:mode="mode"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
v-model:value="efiEnabled"
|
v-model:value="efiEnabled"
|
||||||
class="check"
|
class="check"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:label="t('harvester.virtualMachine.advancedOptions.efiEnabled')"
|
:label="t('harvester.virtualMachine.efiEnabled')"
|
||||||
:mode="mode"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Checkbox
|
|
||||||
v-if="value.efiPersistentStateFeatureEnabled && efiEnabled"
|
|
||||||
v-model:value="efiPersistentStateEnabled"
|
|
||||||
class="check"
|
|
||||||
type="checkbox"
|
|
||||||
:label="t('harvester.virtualMachine.advancedOptions.efiPersistentState')"
|
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -904,10 +886,9 @@ export default {
|
|||||||
v-model:value="secureBoot"
|
v-model:value="secureBoot"
|
||||||
class="check"
|
class="check"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:label="t('harvester.virtualMachine.advancedOptions.secureBoot')"
|
:label="t('harvester.virtualMachine.secureBoot')"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Banner
|
<Banner
|
||||||
v-if="showCpuPinningBanner"
|
v-if="showCpuPinningBanner"
|
||||||
color="warning"
|
color="warning"
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default {
|
|||||||
const rows = (this.value || []).map((row) => {
|
const rows = (this.value || []).map((row) => {
|
||||||
let type = 'cidr';
|
let type = 'cidr';
|
||||||
|
|
||||||
if (row.rangeStart && row.rangeEnd) {
|
if (row.rangeStart || row.rangeEnd) {
|
||||||
type = 'range';
|
type = 'range';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export default {
|
|||||||
:labels="[t('generic.disabled'),t('generic.enabled')]"
|
:labels="[t('generic.disabled'),t('generic.enabled')]"
|
||||||
:options="[false, true]"
|
:options="[false, true]"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@input="onToggle"
|
@update:value="onToggle"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import harvesterCommonStore from './store/harvester-common';
|
|||||||
import harvesterStore from './store/harvester-store';
|
import harvesterStore from './store/harvester-store';
|
||||||
import customValidators from './validators';
|
import customValidators from './validators';
|
||||||
import { PRODUCT_NAME } from './config/harvester';
|
import { PRODUCT_NAME } from './config/harvester';
|
||||||
|
import { defineAsyncComponent } from 'vue';
|
||||||
|
|
||||||
// Init the package
|
// Init the package
|
||||||
export default function (plugin: IPlugin) {
|
export default function (plugin: IPlugin) {
|
||||||
@@ -28,4 +29,8 @@ export default function (plugin: IPlugin) {
|
|||||||
plugin.validators = customValidators;
|
plugin.validators = customValidators;
|
||||||
|
|
||||||
plugin.addRoutes(extensionRoutes);
|
plugin.addRoutes(extensionRoutes);
|
||||||
|
|
||||||
|
plugin.register('component', 'NavHeaderRight', defineAsyncComponent(() =>
|
||||||
|
import('./components/HarvesterUpgradeHeader.vue')
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,21 +38,6 @@ asyncButton:
|
|||||||
success: Restarted
|
success: Restarted
|
||||||
waiting: Restarting…
|
waiting: Restarting…
|
||||||
|
|
||||||
dialog:
|
|
||||||
confirmExecution:
|
|
||||||
title: Are you sure?
|
|
||||||
andOthers: |-
|
|
||||||
{count, plural,
|
|
||||||
=0 {}
|
|
||||||
=1 { and <b>one other </b>}
|
|
||||||
other { and <b>{count} other </b>}
|
|
||||||
}
|
|
||||||
protip: "Tip: Hold the {alternateLabel} key while clicking action to bypass this confirmation"
|
|
||||||
stop:
|
|
||||||
message: "Are you sure you want to continue stop the {type} {names}?"
|
|
||||||
pause:
|
|
||||||
message: "Are you sure you want to continue pause the {type} {names}?"
|
|
||||||
|
|
||||||
harvester:
|
harvester:
|
||||||
branding:
|
branding:
|
||||||
logos:
|
logos:
|
||||||
@@ -599,17 +584,15 @@ harvester:
|
|||||||
enableUsb: Enable USB Tablet
|
enableUsb: Enable USB Tablet
|
||||||
advancedOptions:
|
advancedOptions:
|
||||||
tpm: Enable TPM
|
tpm: Enable TPM
|
||||||
tpmPersistentState: TPM Persistent State
|
|
||||||
cpuManager:
|
cpuManager:
|
||||||
prefix: You must enable CPU Manager for at least one node in
|
prefix: You must enable CPU Manager for at least one node in
|
||||||
middle: 'host page'
|
middle: 'host page'
|
||||||
suffix: to enable CPU Pinning for VM
|
suffix: to enable CPU Pinning for VM
|
||||||
efiEnabled: Booting in EFI mode
|
|
||||||
efiPersistentState: EFI Persistent State
|
|
||||||
secureBoot: Secure Boot
|
|
||||||
usbTip: Provides an absolute pointer device which often helps with getting a consistent mouse cursor position in VNC.
|
usbTip: Provides an absolute pointer device which often helps with getting a consistent mouse cursor position in VNC.
|
||||||
sshTitle: Add Public SSH Key
|
sshTitle: Add Public SSH Key
|
||||||
imageTip: An external URL to the .iso, .img, .qcow2 or .raw that the virtual machine should be created from.
|
imageTip: An external URL to the .iso, .img, .qcow2 or .raw that the virtual machine should be created from.
|
||||||
|
efiEnabled: Booting in EFI mode
|
||||||
|
secureBoot: Secure Boot
|
||||||
volume:
|
volume:
|
||||||
dragTip: Drag and drop volumes, or use the volume's arrows, to change the boot order.
|
dragTip: Drag and drop volumes, or use the volume's arrows, to change the boot order.
|
||||||
volumeTip: The virtual machine only contains a CD-ROM volume. You may want to add additional disk volumes.
|
volumeTip: The virtual machine only contains a CD-ROM volume. You may want to add additional disk volumes.
|
||||||
@@ -855,7 +838,6 @@ harvester:
|
|||||||
currentVersion: CURRENT VERSION
|
currentVersion: CURRENT VERSION
|
||||||
versionLabel: AVAILABLE COMPATIBLE VERSIONS
|
versionLabel: AVAILABLE COMPATIBLE VERSIONS
|
||||||
enableLogging: Enable Logging
|
enableLogging: Enable Logging
|
||||||
skipSingleReplicaDetachedVol: Skip checking single-replica detached volumes
|
|
||||||
upgradeNode: Upgrading Node
|
upgradeNode: Upgrading Node
|
||||||
upgradeSysService: Upgrading System Service
|
upgradeSysService: Upgrading System Service
|
||||||
upgradeImage: Download Upgrade Image
|
upgradeImage: Download Upgrade Image
|
||||||
@@ -920,6 +902,9 @@ harvester:
|
|||||||
label: Virtual Machine Backups
|
label: Virtual Machine Backups
|
||||||
createText: Restore Backup
|
createText: Restore Backup
|
||||||
title: Restore Virtual Machine
|
title: Restore Virtual Machine
|
||||||
|
refreshInterval:
|
||||||
|
label: Refresh Interval
|
||||||
|
tip: The interval for the backup target to sync data to harvester cluster. Set to 0 to disable refresh mechanism.
|
||||||
backupTargetTip: The endpoint used to access the backupstore. NFS and S3 are supported.
|
backupTargetTip: The endpoint used to access the backupstore. NFS and S3 are supported.
|
||||||
message:
|
message:
|
||||||
noSetting:
|
noSetting:
|
||||||
@@ -1029,7 +1014,7 @@ harvester:
|
|||||||
invalid: '"Exclude list" is invalid.'
|
invalid: '"Exclude list" is invalid.'
|
||||||
addIp: Add Exclude IP
|
addIp: Add Exclude IP
|
||||||
warning: 'WARNING: <br/> Any change to storage-network requires shutting down all virtual machines before applying this setting. <br/> Users have to ensure the cluster network is configured and VLAN Configuration will cover all nodes and ensure the network connectivity is working and expected in all nodes.'
|
warning: 'WARNING: <br/> Any change to storage-network requires shutting down all virtual machines before applying this setting. <br/> Users have to ensure the cluster network is configured and VLAN Configuration will cover all nodes and ensure the network connectivity is working and expected in all nodes.'
|
||||||
tip: 'Specify an IP range in the IPv4 CIDR format. <code>Number of IPs Required = Number of Nodes * 2 + Number of Disks * 2 + Number of Images to Download/Upload </code>. For more information about storage network settings, see the <a href="{url}" target="_blank">documentation</a>.'
|
tip: 'Specify an IP range in the IPv4 CIDR format. <code>Number of IPs Required = Number of Nodes * 4 + Number of Disks * 2 + Number of Images to Download/Upload </code>. For more information about storage network settings, see the <a href="{url}" target="_blank">documentation</a>.'
|
||||||
vmForceDeletionPolicy:
|
vmForceDeletionPolicy:
|
||||||
period: Period
|
period: Period
|
||||||
ratio : Ratio
|
ratio : Ratio
|
||||||
|
|||||||
@@ -137,15 +137,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
isTpmEnabled(spec) {
|
isTpmEnabled(spec) {
|
||||||
return !!spec?.template?.spec?.domain?.devices?.tpm;
|
return !!spec?.template?.spec?.domain?.devices?.tpm ;
|
||||||
},
|
|
||||||
|
|
||||||
isTPMPersistentStateEnabled(spec) {
|
|
||||||
return !!spec?.template?.spec?.domain?.devices?.tpm?.persistent;
|
|
||||||
},
|
|
||||||
|
|
||||||
isEFIPersistentStateEnabled(spec) {
|
|
||||||
return !!spec?.template?.spec?.domain?.firmware?.bootloader?.efi?.persistent;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
isSecureBoot(spec) {
|
isSecureBoot(spec) {
|
||||||
|
|||||||
@@ -164,8 +164,6 @@ export default {
|
|||||||
accessCredentials: [],
|
accessCredentials: [],
|
||||||
efiEnabled: false,
|
efiEnabled: false,
|
||||||
tpmEnabled: false,
|
tpmEnabled: false,
|
||||||
tpmPersistentStateEnabled: false,
|
|
||||||
efiPersistentStateEnabled: false,
|
|
||||||
secureBoot: false,
|
secureBoot: false,
|
||||||
userDataTemplateId: '',
|
userDataTemplateId: '',
|
||||||
saveUserDataAsClearText: false,
|
saveUserDataAsClearText: false,
|
||||||
@@ -219,7 +217,7 @@ export default {
|
|||||||
const selectedVMNetworks = networkNames.map((name) => vmNetworks.find((n) => n.id === name)).filter((n) => n?.id);
|
const selectedVMNetworks = networkNames.map((name) => vmNetworks.find((n) => n.id === name)).filter((n) => n?.id);
|
||||||
const clusterNetworks = uniq(selectedVMNetworks.map((n) => n.clusterNetworkResource?.id));
|
const clusterNetworks = uniq(selectedVMNetworks.map((n) => n.clusterNetworkResource?.id));
|
||||||
|
|
||||||
return nodes.filter((N) => !N.isUnSchedulable && N.isEtcd !== 'true').map((node) => {
|
return nodes.filter((N) => !N.isUnSchedulable).map((node) => {
|
||||||
const requireLabelKeys = [];
|
const requireLabelKeys = [];
|
||||||
let isNetworkSchedule = true;
|
let isNetworkSchedule = true;
|
||||||
|
|
||||||
@@ -369,8 +367,6 @@ export default {
|
|||||||
const installAgent = this.hasInstallAgent(userData, osType, true);
|
const installAgent = this.hasInstallAgent(userData, osType, true);
|
||||||
const efiEnabled = this.isEfiEnabled(spec);
|
const efiEnabled = this.isEfiEnabled(spec);
|
||||||
const tpmEnabled = this.isTpmEnabled(spec);
|
const tpmEnabled = this.isTpmEnabled(spec);
|
||||||
const tpmPersistentStateEnabled = this.isTPMPersistentStateEnabled(spec);
|
|
||||||
const efiPersistentStateEnabled = this.isEFIPersistentStateEnabled(spec);
|
|
||||||
const secureBoot = this.isSecureBoot(spec);
|
const secureBoot = this.isSecureBoot(spec);
|
||||||
const cpuPinning = this.isCpuPinning(spec);
|
const cpuPinning = this.isCpuPinning(spec);
|
||||||
|
|
||||||
@@ -402,9 +398,7 @@ export default {
|
|||||||
|
|
||||||
this['installUSBTablet'] = installUSBTablet;
|
this['installUSBTablet'] = installUSBTablet;
|
||||||
this['efiEnabled'] = efiEnabled;
|
this['efiEnabled'] = efiEnabled;
|
||||||
this['efiPersistentStateEnabled'] = efiPersistentStateEnabled;
|
|
||||||
this['tpmEnabled'] = tpmEnabled;
|
this['tpmEnabled'] = tpmEnabled;
|
||||||
this['tpmPersistentStateEnabled'] = tpmPersistentStateEnabled;
|
|
||||||
this['secureBoot'] = secureBoot;
|
this['secureBoot'] = secureBoot;
|
||||||
this['cpuPinning'] = cpuPinning;
|
this['cpuPinning'] = cpuPinning;
|
||||||
|
|
||||||
@@ -900,8 +894,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate user data yaml which is decide by the "Install guest agent",
|
* Generate user data yaml which is decided by the
|
||||||
* "OS type", "SSH Keys" and user input.
|
* "Install guest agent", "OS type", "SSH keys" and user input.
|
||||||
* @param config
|
* @param config
|
||||||
*/
|
*/
|
||||||
getUserData(config) {
|
getUserData(config) {
|
||||||
@@ -925,7 +919,9 @@ export default {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return userDataYaml;
|
const hasCloudComment = this.hasCloudConfigComment(userDataYaml);
|
||||||
|
|
||||||
|
return hasCloudComment ? userDataYaml : `#cloud-config\n${ userDataYaml }`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error: Unable to parse yaml document', e); // eslint-disable-line no-console
|
console.error('Error: Unable to parse yaml document', e); // eslint-disable-line no-console
|
||||||
|
|
||||||
@@ -1218,7 +1214,6 @@ export default {
|
|||||||
|
|
||||||
let secret = this.getSecret(vm.spec);
|
let secret = this.getSecret(vm.spec);
|
||||||
|
|
||||||
// const userData = this.getUserData({ osType: this.osType, installAgent: this.installAgent });
|
|
||||||
if (!secret && this.isEdit && this.secretRef) {
|
if (!secret && this.isEdit && this.secretRef) {
|
||||||
// When editing the vm, if the userData and networkData are deleted, we also need to clean up the secret values
|
// When editing the vm, if the userData and networkData are deleted, we also need to clean up the secret values
|
||||||
secret = this.secretRef;
|
secret = this.secretRef;
|
||||||
@@ -1389,21 +1384,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setBootMethod(boot = {
|
setBootMethod(boot = { efi: false, secureBoot: false }) {
|
||||||
efi: false, secureBoot: false, efiPersistentStateEnabled: false
|
if (boot.efi && boot.secureBoot) {
|
||||||
}) {
|
|
||||||
if (boot.efi) {
|
|
||||||
set(this.spec.template.spec.domain, 'firmware.bootloader.efi.secureBoot', boot.secureBoot);
|
|
||||||
} else {
|
|
||||||
delete this.spec.template.spec.domain['firmware'];
|
|
||||||
delete this.spec.template.spec.domain.features['smm'];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boot.secureBoot) {
|
|
||||||
set(this.spec.template.spec.domain, 'features.smm.enabled', true);
|
set(this.spec.template.spec.domain, 'features.smm.enabled', true);
|
||||||
} else {
|
set(this.spec.template.spec.domain, 'firmware.bootloader.efi.secureBoot', true);
|
||||||
|
} else if (boot.efi && !boot.secureBoot) {
|
||||||
|
// set(this.spec.template.spec.domain, 'features.smm.enabled', false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
delete this.spec.template.spec.domain.features.smm['enabled'];
|
delete this.spec.template.spec.domain.features.smm['enabled'];
|
||||||
const noKeys = Object.keys(this.spec.template.spec.domain.features.smm).length === 0;
|
const noKeys = Object.keys(this.spec.template.spec.domain.features.smm).length === 0;
|
||||||
@@ -1412,12 +1399,10 @@ export default {
|
|||||||
delete this.spec.template.spec.domain.features['smm'];
|
delete this.spec.template.spec.domain.features['smm'];
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
set(this.spec.template.spec.domain, 'firmware.bootloader.efi.secureBoot', false);
|
||||||
|
|
||||||
if (boot.efiPersistentStateEnabled) {
|
|
||||||
set(this.spec.template.spec.domain, 'firmware.bootloader.efi.persistent', true);
|
|
||||||
} else {
|
} else {
|
||||||
delete this.spec.template.spec.domain.firmware.bootloader.efi['persistent'];
|
delete this.spec.template.spec.domain['firmware'];
|
||||||
|
delete this.spec.template.spec.domain.features['smm'];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1429,9 +1414,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setTPM({ tpmEnabled = false, tpmPersistentStateEnabled = false } = {}) {
|
setTPM(tpmEnabled) {
|
||||||
if (tpmEnabled) {
|
if (tpmEnabled) {
|
||||||
set(this.spec.template.spec.domain.devices, 'tpm', tpmPersistentStateEnabled ? { persistent: true } : {});
|
set(this.spec.template.spec.domain.devices, 'tpm', {});
|
||||||
} else {
|
} else {
|
||||||
delete this.spec.template.spec.domain.devices['tpm'];
|
delete this.spec.template.spec.domain.devices['tpm'];
|
||||||
}
|
}
|
||||||
@@ -1447,7 +1432,6 @@ export default {
|
|||||||
sshAuthorizedKeys.splice(index, 1);
|
sshAuthorizedKeys.splice(index, 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const userDataJson = this.convertToJson(this.userScript);
|
const userDataJson = this.convertToJson(this.userScript);
|
||||||
|
|
||||||
userDataJson.ssh_authorized_keys = sshAuthorizedKeys;
|
userDataJson.ssh_authorized_keys = sshAuthorizedKeys;
|
||||||
@@ -1545,21 +1529,11 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
efiEnabled(val) {
|
efiEnabled(val) {
|
||||||
this.setBootMethod({
|
this.setBootMethod({ efi: val, secureBoot: this.secureBoot });
|
||||||
efi: val, secureBoot: this.secureBoot, efiPersistentStateEnabled: this.efiPersistentStateEnabled
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
secureBoot(val) {
|
secureBoot(val) {
|
||||||
this.setBootMethod({
|
this.setBootMethod({ efi: this.efiEnabled, secureBoot: val });
|
||||||
efi: this.efiEnabled, secureBoot: val, efiPersistentStateEnabled: this.efiPersistentStateEnabled
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
efiPersistentStateEnabled(val) {
|
|
||||||
this.setBootMethod({
|
|
||||||
efi: this.efiEnabled, secureBoot: this.secureBoot, efiPersistentStateEnabled: val
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cpuPinning(value) {
|
cpuPinning(value) {
|
||||||
@@ -1567,11 +1541,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
tpmEnabled(val) {
|
tpmEnabled(val) {
|
||||||
this.setTPM({ tpmEnabled: val, tpmPersistentStateEnabled: this.tpmPersistentStateEnabled });
|
this.setTPM(val);
|
||||||
},
|
|
||||||
|
|
||||||
tpmPersistentStateEnabled(val) {
|
|
||||||
this.setTPM({ tpmEnabled: this.tpmEnabled, tpmPersistentStateEnabled: val });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
installAgent: {
|
installAgent: {
|
||||||
@@ -1583,19 +1553,9 @@ export default {
|
|||||||
*/
|
*/
|
||||||
handler(neu) {
|
handler(neu) {
|
||||||
if (this.deleteAgent) {
|
if (this.deleteAgent) {
|
||||||
let out = this.getUserData({
|
this['userScript'] = this.getUserData({
|
||||||
installAgent: neu, osType: this.osType, deletePackage: this.deletePackage
|
installAgent: neu, osType: this.osType, deletePackage: this.deletePackage
|
||||||
});
|
});
|
||||||
|
|
||||||
if (neu) {
|
|
||||||
const hasCloudComment = this.hasCloudConfigComment(out);
|
|
||||||
|
|
||||||
if (!hasCloudComment) {
|
|
||||||
out = `#cloud-config\n${ out }`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this['userScript'] = out;
|
|
||||||
this.refreshYamlEditor();
|
this.refreshYamlEditor();
|
||||||
}
|
}
|
||||||
this.deleteAgent = true;
|
this.deleteAgent = true;
|
||||||
@@ -1622,9 +1582,14 @@ export default {
|
|||||||
sshKey(neu, old) {
|
sshKey(neu, old) {
|
||||||
const _diff = difference(old, neu);
|
const _diff = difference(old, neu);
|
||||||
|
|
||||||
if (_diff.length && this.isEdit) {
|
// delete removed ssh key in userdata if needed
|
||||||
|
if (_diff.length > 0 && this.isCreate) {
|
||||||
this.deleteSSHFromUserData(_diff);
|
this.deleteSSHFromUserData(_diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// refresh yaml editor to get the latest userScript
|
||||||
|
this.userScript = this.getUserData({ installAgent: this.installAgent, osType: this.osType });
|
||||||
|
this.refreshYamlEditor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing PCI Device Claim resource.
|
||||||
|
* @extends SteveModal
|
||||||
|
*/
|
||||||
|
export default class PCIDeviceClaim extends SteveModel {
|
||||||
|
cleanForSave(data, _forNew) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing USB Device Claim resource.
|
||||||
|
* @extends SteveModal
|
||||||
|
*/
|
||||||
|
export default class USBDeviceClaim extends SteveModel {
|
||||||
|
cleanForSave(data, _forNew) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,4 +66,8 @@ export default class HarvesterResource extends SteveModel {
|
|||||||
return this.hasLink('self') && this.$rootGetters['prefs/get'](DEV);
|
return this.hasLink('self') && this.$rootGetters['prefs/get'](DEV);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanForSave(data, _forNew) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ export default class HciNode extends HarvesterResource {
|
|||||||
get canDelete() {
|
get canDelete() {
|
||||||
const nodes = this.$rootGetters['harvester/all'](NODE) || [];
|
const nodes = this.$rootGetters['harvester/all'](NODE) || [];
|
||||||
|
|
||||||
return nodes.length > 1 && super.canDelete;
|
return nodes.length > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
get vlanStatuses() {
|
get vlanStatuses() {
|
||||||
|
|||||||
@@ -58,10 +58,6 @@ export default class HciStorageClass extends StorageClass {
|
|||||||
return key ? this.$rootGetters['i18n/t'](key) : this.provisioner;
|
return key ? this.$rootGetters['i18n/t'](key) : this.provisioner;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isEncrypted() {
|
|
||||||
return this.parameters?.encrypted === 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
get isLonghornV2() {
|
get isLonghornV2() {
|
||||||
return this.provisioner === LONGHORN_DRIVER && this.longhornVersion === DATA_ENGINE_V2;
|
return this.provisioner === LONGHORN_DRIVER && this.longhornVersion === DATA_ENGINE_V2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ export default class HciUpgrade extends HarvesterResource {
|
|||||||
return this?.status?.imageID;
|
return this?.status?.imageID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanForSave(data, _forNew) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
get upgradeMessage() {
|
get upgradeMessage() {
|
||||||
const upgradeMessage = [];
|
const upgradeMessage = [];
|
||||||
const nodeStatuses = this?.status?.nodeStatuses || {};
|
const nodeStatuses = this?.status?.nodeStatuses || {};
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export default class HciVmBackup extends HarvesterResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get sourceSchedule() {
|
get sourceSchedule() {
|
||||||
return this.metadata?.annotations?.[HCI_ANNOTATIONS.SVM_BACKUP_ID];
|
return this.metadata?.annotations[HCI_ANNOTATIONS.SVM_BACKUP_ID];
|
||||||
}
|
}
|
||||||
|
|
||||||
get attachVM() {
|
get attachVM() {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { MODE, _CREATE } from '@shell/config/query-params';
|
|||||||
import { HCI } from '../types';
|
import { HCI } from '../types';
|
||||||
import { PRODUCT_NAME as HARVESTER_PRODUCT } from '../config/harvester';
|
import { PRODUCT_NAME as HARVESTER_PRODUCT } from '../config/harvester';
|
||||||
import HarvesterResource from './harvester';
|
import HarvesterResource from './harvester';
|
||||||
|
import { clone } from '@shell/utils/object';
|
||||||
|
|
||||||
export default class HciVmTemplate extends HarvesterResource {
|
export default class HciVmTemplate extends HarvesterResource {
|
||||||
get availableActions() {
|
get availableActions() {
|
||||||
@@ -71,4 +72,12 @@ export default class HciVmTemplate extends HarvesterResource {
|
|||||||
get defaultVersion() {
|
get defaultVersion() {
|
||||||
return this.status?.defaultVersion;
|
return this.status?.defaultVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get doneOverride() {
|
||||||
|
const detailLocation = clone(this.listLocation);
|
||||||
|
|
||||||
|
detailLocation.params.resource = HCI.VM_VERSION;
|
||||||
|
|
||||||
|
return detailLocation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,10 +210,6 @@ export default class HciVmTemplateVersion extends HarvesterResource {
|
|||||||
await templateResource.save();
|
await templateResource.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
get cpuPinningFeatureEnabled() {
|
|
||||||
return this.$rootGetters['harvester-common/getFeatureEnabled']('cpuPinning');
|
|
||||||
}
|
|
||||||
|
|
||||||
get defaultVersion() {
|
get defaultVersion() {
|
||||||
const templates = this.$rootGetters['harvester/all'](HCI.VM_TEMPLATE);
|
const templates = this.$rootGetters['harvester/all'](HCI.VM_TEMPLATE);
|
||||||
const template = templates.find((T) => this.templateId === T.id);
|
const template = templates.find((T) => this.templateId === T.id);
|
||||||
@@ -276,12 +272,4 @@ export default class HciVmTemplateVersion extends HarvesterResource {
|
|||||||
|
|
||||||
this.spec.vm.spec.template.metadata['labels'] = { ...wasIgnored, ...val };
|
this.spec.vm.spec.template.metadata['labels'] = { ...wasIgnored, ...val };
|
||||||
}
|
}
|
||||||
|
|
||||||
get tpmPersistentStateFeatureEnabled() {
|
|
||||||
return this.$rootGetters['harvester-common/getFeatureEnabled']('tpmPersistentState');
|
|
||||||
}
|
|
||||||
|
|
||||||
get efiPersistentStateFeatureEnabled() {
|
|
||||||
return this.$rootGetters['harvester-common/getFeatureEnabled']('efiPersistentState');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import SteveModel from '@shell/plugins/steve/steve-class';
|
import SteveModel from '@shell/plugins/steve/steve-class';
|
||||||
import { HCI } from '@shell/config/labels-annotations';
|
import { HCI } from '@shell/config/labels-annotations';
|
||||||
import { NETWORK_TYPE } from '../config/types';
|
|
||||||
|
|
||||||
const { UNTAGGED } = NETWORK_TYPE;
|
|
||||||
|
|
||||||
export default class NetworkAttachmentDef extends SteveModel {
|
export default class NetworkAttachmentDef extends SteveModel {
|
||||||
applyDefaults() {
|
applyDefaults() {
|
||||||
@@ -45,7 +42,7 @@ export default class NetworkAttachmentDef extends SteveModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get vlanId() {
|
get vlanId() {
|
||||||
return this.vlanType === UNTAGGED ? 'N/A' : this.parseConfig.vlan;
|
return this.vlanType === 'UntaggedNetwork' ? 'N/A' : this.parseConfig.vlan;
|
||||||
}
|
}
|
||||||
|
|
||||||
get customValidationRules() {
|
get customValidationRules() {
|
||||||
@@ -68,7 +65,7 @@ export default class NetworkAttachmentDef extends SteveModel {
|
|||||||
const route = annotations[HCI.NETWORK_ROUTE];
|
const route = annotations[HCI.NETWORK_ROUTE];
|
||||||
let config = {};
|
let config = {};
|
||||||
|
|
||||||
if (this.vlanType === UNTAGGED) {
|
if (this.vlanType === 'UntaggedNetwork') {
|
||||||
return 'N/A';
|
return 'N/A';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,13 +102,11 @@ export default class VirtVm extends HarvesterResource {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
action: 'stopVM',
|
action: 'stopVM',
|
||||||
altAction: 'altStopVM',
|
enabled: !!this.actions?.stop,
|
||||||
enabled: !!this.actions?.stop,
|
icon: 'icon icon-close',
|
||||||
icon: 'icon icon-close',
|
label: this.t('harvester.action.stop'),
|
||||||
label: this.t('harvester.action.stop'),
|
bulkable: true
|
||||||
bulkable: true,
|
|
||||||
bulkAction: 'stopVM',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
action: 'forceStop',
|
action: 'forceStop',
|
||||||
@@ -118,11 +116,10 @@ export default class VirtVm extends HarvesterResource {
|
|||||||
bulkable: true
|
bulkable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
action: 'pauseVM',
|
action: 'pauseVM',
|
||||||
altAction: 'altPauseVM',
|
enabled: !!this.actions?.pause,
|
||||||
enabled: !!this.actions?.pause,
|
icon: 'icon icon-pause',
|
||||||
icon: 'icon icon-pause',
|
label: this.t('harvester.action.pause')
|
||||||
label: this.t('harvester.action.pause')
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
action: 'unpauseVM',
|
action: 'unpauseVM',
|
||||||
@@ -405,16 +402,7 @@ export default class VirtVm extends HarvesterResource {
|
|||||||
return node?.id;
|
return node?.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pauseVM(resources = this) {
|
pauseVM() {
|
||||||
this.$dispatch('promptModal', {
|
|
||||||
resources,
|
|
||||||
action: 'pause',
|
|
||||||
warningMessageKey: 'dialog.confirmExecution.pause.message',
|
|
||||||
component: 'ConfirmExecutionDialog'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
altPauseVM() {
|
|
||||||
this.doActionGrowl('pause', {});
|
this.doActionGrowl('pause', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,16 +417,7 @@ export default class VirtVm extends HarvesterResource {
|
|||||||
this.doActionGrowl('unpause', {});
|
this.doActionGrowl('unpause', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
stopVM(resources = this) {
|
stopVM() {
|
||||||
this.$dispatch('promptModal', {
|
|
||||||
resources,
|
|
||||||
action: 'stop',
|
|
||||||
warningMessageKey: 'dialog.confirmExecution.stop.message',
|
|
||||||
component: 'ConfirmExecutionDialog'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
altStopVM() {
|
|
||||||
this.doActionGrowl('stop', {});
|
this.doActionGrowl('stop', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,10 +619,6 @@ export default class VirtVm extends HarvesterResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get encryptedVolumeType() {
|
get encryptedVolumeType() {
|
||||||
if (!this.volumes || this.volumes.length === 0) {
|
|
||||||
return 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.volumes.every((vol) => vol.isEncrypted)) {
|
if (this.volumes.every((vol) => vol.isEncrypted)) {
|
||||||
return 'all';
|
return 'all';
|
||||||
} else if (this.volumes.some((vol) => vol.isEncrypted)) {
|
} else if (this.volumes.some((vol) => vol.isEncrypted)) {
|
||||||
@@ -1175,14 +1150,6 @@ export default class VirtVm extends HarvesterResource {
|
|||||||
return this.$rootGetters['harvester-common/getFeatureEnabled']('volumeEncryption');
|
return this.$rootGetters['harvester-common/getFeatureEnabled']('volumeEncryption');
|
||||||
}
|
}
|
||||||
|
|
||||||
get tpmPersistentStateFeatureEnabled() {
|
|
||||||
return this.$rootGetters['harvester-common/getFeatureEnabled']('tpmPersistentState');
|
|
||||||
}
|
|
||||||
|
|
||||||
get efiPersistentStateFeatureEnabled() {
|
|
||||||
return this.$rootGetters['harvester-common/getFeatureEnabled']('efiPersistentState');
|
|
||||||
}
|
|
||||||
|
|
||||||
setInstanceLabels(val) {
|
setInstanceLabels(val) {
|
||||||
if ( !this.spec?.template?.metadata?.labels ) {
|
if ( !this.spec?.template?.metadata?.labels ) {
|
||||||
set(this, 'spec.template.metadata.labels', {});
|
set(this, 'spec.template.metadata.labels', {});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "harvester",
|
"name": "harvester",
|
||||||
"description": "Rancher UI Extension for Harvester",
|
"description": "Rancher UI Extension for Harvester",
|
||||||
"version": "1.0.3",
|
"version": "1.0.6",
|
||||||
"private": false,
|
"private": false,
|
||||||
"rancher": {
|
"rancher": {
|
||||||
"annotations": {
|
"annotations": {
|
||||||
|
|||||||
Reference in New Issue
Block a user