diff --git a/.env.development b/.env.development index 272779e3..838e910c 100644 --- a/.env.development +++ b/.env.development @@ -7,4 +7,6 @@ ADDONS_JSON="https://kurl-sh.s3.amazonaws.com/staging/addons-gen.json" IS_DEVELOPMENT="true" BUGSNAG_API_KEY="d9853b1ecad8ac8750308fe7ce9335b8" BUGSNAG_RELEASE_STAGE="development" -BUGSNAG_DISABLE="true" \ No newline at end of file +BUGSNAG_DISABLE="true" +GATSBY_ALGOLIA_APP_ID = "UB8IN95AB5" +GATSBY_ALGOLIA_API_KEY = "4bcf277e75d8f888739aa06079fdb19d" diff --git a/.env.production b/.env.production index a7ecc5ae..706905b8 100644 --- a/.env.production +++ b/.env.production @@ -8,4 +8,6 @@ GOOGLE_ANALYTICS_TRACKING_ID="UA-61420213-15" MATOMO_SITE_ID="11" MATOMO_URL="data-2.replicated.com" BUGSNAG_API_KEY="d9853b1ecad8ac8750308fe7ce9335b8" -BUGSNAG_RELEASE_STAGE="production" \ No newline at end of file +BUGSNAG_RELEASE_STAGE="production" +GATSBY_ALGOLIA_APP_ID = "UB8IN95AB5" +GATSBY_ALGOLIA_API_KEY = "4bcf277e75d8f888739aa06079fdb19d" diff --git a/.env.staging b/.env.staging index ee9acb98..7b6e4a15 100644 --- a/.env.staging +++ b/.env.staging @@ -8,4 +8,6 @@ GOOGLE_ANALYTICS_TRACKING_ID="UA-61420213-15" MATOMO_SITE_ID="11" MATOMO_URL="data-2.staging.replicated.com" BUGSNAG_API_KEY="d9853b1ecad8ac8750308fe7ce9335b8" -BUGSNAG_RELEASE_STAGE="staging" \ No newline at end of file +BUGSNAG_RELEASE_STAGE="staging" +GATSBY_ALGOLIA_APP_ID = "UB8IN95AB5" +GATSBY_ALGOLIA_API_KEY = "4bcf277e75d8f888739aa06079fdb19d" diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 00000000..a990d6ab --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,21 @@ +--- +version: 2 +updates: + # - package-ecosystem: "npm" + # directory: "/" + # labels: + # - "dependencies" + # - "javascript" + # - "type::chore" + # schedule: + # interval: "monthly" + # open-pull-requests-limit: 25 + + - package-ecosystem: "github-actions" + directory: "/" + labels: + - "dependencies" + - "github-actions" + - "type::chore" + schedule: + interval: "weekly" diff --git a/.github/workflows/algolia-crawl.yaml b/.github/workflows/algolia-crawl.yaml index 9518dd00..f41f82f5 100644 --- a/.github/workflows/algolia-crawl.yaml +++ b/.github/workflows/algolia-crawl.yaml @@ -3,12 +3,13 @@ on: push: branches: release + workflow_dispatch: jobs: scrape: runs-on: ubuntu-latest steps: - name: check out code 🛎d - uses: actions/checkout@v2 + uses: actions/checkout@v4 # when scraping the site, inject secrets as environment variables # then pass their values into the Docker container using "-e" syntax # and inject config.json contents as another variable diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 00000000..f2e7a2c9 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,64 @@ +name: deploy + +on: + push: + branches: + - main + +jobs: + + deploy-staging-netlify: + environment: + name: staging + url: https://staging.kurl.sh + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 16 + cache: yarn + + - name: build + run: make deps build-staging + + - name: release + uses: nwtgck/actions-netlify@v3.0 + with: + publish-dir: public + production-branch: main + github-token: ${{ secrets.GITHUB_TOKEN }} + deploy-message: "Deploy staging.kurl.sh from GitHub Actions" + github-deployment-environment: staging + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: 9cc8b96a-2c23-4f71-bb0f-cbdc19ccbf76 + timeout-minutes: 1 + + deploy-production-netlify: + environment: + name: production + url: https://kurl.sh + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 16 + cache: yarn + + - name: build + run: make deps build-production + + - name: release + uses: nwtgck/actions-netlify@v3.0 + with: + publish-dir: public + production-branch: main + github-token: ${{ secrets.GITHUB_TOKEN }} + deploy-message: "Deploy kurl.sh from GitHub Actions" + github-deployment-environment: production + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: 7e8d8070-273a-45a3-9c84-885a52d8ab69 + timeout-minutes: 1 diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml new file mode 100644 index 00000000..4c98a269 --- /dev/null +++ b/.github/workflows/preview.yaml @@ -0,0 +1,33 @@ +name: preview + +on: + pull_request: + branches: + - main + +jobs: + + deploy-staging-netlify: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 16 + cache: yarn + + - name: build + run: make deps build-staging + + - name: release + uses: nwtgck/actions-netlify@v3.0 + with: + publish-dir: public + production-branch: main + github-token: ${{ secrets.GITHUB_TOKEN }} + deploy-message: "Deploy preview staging.kurl.sh from GitHub Actions" + github-deployment-environment: preview + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: 9cc8b96a-2c23-4f71-bb0f-cbdc19ccbf76 + timeout-minutes: 5 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a6a5f21d..077b93e6 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -7,9 +7,9 @@ jobs: test: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: 16 - - run: npm install -g yarn + cache: yarn - run: make deps test diff --git a/.github/workflows/update-release-notes.yaml b/.github/workflows/update-release-notes.yaml index 96f1bab3..1d7a850c 100644 --- a/.github/workflows/update-release-notes.yaml +++ b/.github/workflows/update-release-notes.yaml @@ -7,7 +7,7 @@ jobs: build-pr-release-notes: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Create Release Notes Template id: release-notes @@ -15,8 +15,8 @@ jobs: KURL_VERSION: ${{ github.event.client_payload.version }} run: | KURL_VERSION=$( echo $KURL_VERSION | sed -E -e 's/v(.*)/\1/g' ) - echo "::set-output name=parsed_kurl_version::$KURL_VERSION" - + echo "parsed_kurl_version=$KURL_VERSION" >> "$GITHUB_OUTPUT" + cp ./hack/release-notes.md.tmpl ./src/release-notes/${KURL_VERSION}.md DATE=$(date +%F) WEIGHT=$(echo $KURL_VERSION | tr -d "v\.\-") @@ -24,7 +24,7 @@ jobs: sed -i "s/__VERSION__/$KURL_VERSION/g" ./content/release-notes/${KURL_VERSION}.md - name: Create Pull Request # creates a PR if there are differences - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v6 id: cpr with: token: ${{ secrets.GITHUB_TOKEN }} @@ -46,7 +46,7 @@ jobs: - name: Slack Notification id: slack - uses: slackapi/slack-github-action@v1.16.0 + uses: slackapi/slack-github-action@v1.26.0 with: payload: "{\"message\":\"Pull request #${{steps.cpr.outputs.pull-request-number }} is ready for kURL.sh release notes: ${{steps.cpr.outputs.pull-request-url}}\",\"version\":\"${{ steps.release-notes.outputs.parsed_kurl_version }}\"}" env: diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..007af1af --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,16 @@ +# Lines starting with '#' are comments. +# Each line is a file pattern followed by one or more owners. + +# More details are here: https://help.github.com/articles/about-codeowners/ + +# The '*' pattern is global owners. + +# Order is important. The last matching pattern has the most precedence. +# The folders are ordered as follows: + +# In each subsection folders are ordered first by depth, then alphabetically. +# This should make it easy to add new rules without breaking existing ones. + +## RULES + +* @replicatedhq/embedded-kubernetes diff --git a/README.md b/README.md index 25755d93..27a8bf49 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,8 @@ Before you are able to run this locally you need to have NodeJS above v.8.12. ## Releasing the documentation -The kurl.sh website is built off of the `release` branch. Pull requests are first created and reviewed so that they can be merged into the `main` branch. Once the needed documentation updates are in `main`, you can create a pull request to merge them into `release`. - -To merge `main` into `release`: -1. Click the [**Pull requests** tab](https://github.com/replicatedhq/kurl.sh/pulls) and click **New pull request**. -1. Change the base branch to `release`. The compare branch should be set to `main`. -1. Click **Create pull request**. -1. Wait for all checks to pass. View the deploy preview to ensure that the changes are correct. -1. Click **Merge pull request**. +The [deploy workflow](https://github.com/replicatedhq/kurl.sh/actions/workflows/deploy.yaml) is responsible for releasing to both staging and production. + +Staging will be released on merge to main. + +Releasing to the production environment requires review from the @replicatedhq/embedded-kubernetes team. diff --git a/gatsby-node.js b/gatsby-node.js index 6b52ffbd..d48d08fb 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -43,6 +43,7 @@ exports.createSchemaCustomization = ({ actions }) => { version: String isBeta: Boolean isAlpha: Boolean + isDeprecated: Boolean } ` createTypes(typeDefs) @@ -87,6 +88,7 @@ exports.createPages = async ({ actions, graphql, reporter }) => { version isBeta isAlpha + isDeprecated } } } diff --git a/package.json b/package.json index e8f0f7dd..6a890542 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "react-router-dom": "^5.0.1", "react-select": "^3.0.5", "react-tooltip": "^3.11.1", - "semver": "^7.3.2" + "semver": "^7.5.2" }, "devDependencies": { "@babel/core": "^7.19.3", @@ -77,5 +77,53 @@ "webpack": "^4.39.3", "webpack-cli": "^3.3.8", "webpack-dev-server": "^3.8.0" + }, + "resolutions": { + "minimist": "^1.2.8", + "flat": "^5.0.2", + "socket.io-parser": "^3.4.2", + "loader-utils": "^1.4.1", + "parse-url": "^8.1.0", + "shell-quote": "^1.7.3", + "eventsource": "^1.1.1", + "xmlhttprequest-ssl": "^1.6.1", + "body-parser": "^1.20.3", + "glob-parent": "^5.1.2", + "socket.io": "^2.5.1", + "node-forge": "^1.3.0", + "follow-redirects": "^1.14.7", + "sanitize-html": "^2.7.1", + "ws": "^7.5.10", + "axios": "^0.21.2", + "mermaid": "^8.13.8", + "object-path": "^0.11.8", + "@braintree/sanitize-url": "^6.0.1", + "ansi-regex": "^5.0.1", + "debug": "^4.3.4", + "engine.io": "^3.6.1", + "express": "^4.20.0", + "hosted-git-info": "^3.0.8", + "is-svg": "^4.3.0", + "json5": "^2.2.2", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "semver": "^7.5.2", + "@hapi/hoek": "^8.5.1", + "acorn": "^6.4.1", + "ansi-html": "^0.0.8", + "braces": "^3.0.3", + "d3-color": "^3.1.0", + "dns-packet": "^1.3.2", + "graphql-playground-html": "^1.6.22", + "http-cache-semantics": "^4.1.1", + "kind-of": "^6.0.3", + "minimatch": "^3.0.5", + "node-fetch": "^2.6.7", + "nth-check": "^2.0.1", + "serialize-javascript": "^6.0.0", + "terser": "^4.8.1", + "trim": "^0.0.3", + "websocket-extensions": "^0.1.4", + "y18n": "^5.0.5" } } diff --git a/src/components/AddOnWrapper.js b/src/components/AddOnWrapper.js deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/App.js b/src/components/App.js index c50d8639..498d8206 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -185,16 +185,19 @@ cat install.sh | sudo bash -s airgap Ubuntu 18.04
  • - Ubuntu 20.04 (Docker version >= 19.03.10) + Ubuntu 20.04 (Docker version {'>'}= 19.03.10)
  • - CentOS 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.1, 8.2, 8.3 (CentOS 8.x requires Containerd) + CentOS 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.1, 8.2, 8.3, 8.4 (CentOS 8.x requires Containerd)
  • - RHEL 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6 (RHEL 8.x requires Containerd) + RHEL 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 9.0, 9.1, 9.2 (RHEL 8.x and 9.x require Containerd)
  • - Oracle Linux 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6 (OL 8.x requires Containerd) + Rocky Linux 9.0, 9.1, 9.2 (Rocky Linux 9.x requires Containerd) +
  • +
  • + Oracle Linux 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8 (OL 8.x requires Containerd)
  • Amazon Linux 2 @@ -211,17 +214,45 @@ cat install.sh | sudo bash -s airgap 4 CPUs or equivalent per machine
  • - 30 GB of Disk Space per machine + 8 GB of RAM per machine
  • - UDP ports 6783 and 6784 open + 30 GB of Disk Space per machine
  • + {installerData && installerData.spec.flannel && installerData.spec.flannel.version &&
  • - 8 GB of RAM per machine -
  • + TCP ports 2379, 2380, 6443, 10250, 10257 and 10259 open between cluster nodes + } + {installerData && installerData.spec.flannel && installerData.spec.flannel.version &&
  • - TCP ports 6443 and 6783 open -
  • + UDP port 8472 open between cluster nodes + } + {installerData && installerData.spec.weave && installerData.spec.weave.version && +
  • + TCP ports 2379, 2380, 6443, 6783, 10250, 10257 and 10259 open between cluster nodes +
  • } + {installerData && installerData.spec.weave && installerData.spec.weave.version && +
  • + UDP ports 6783 and 6784 open between cluster nodes +
  • } + {installerData && installerData.spec.antrea && installerData.spec.antrea.version && +
  • + {installerData.spec.antrea.isEncryptionDisabled ? + + TCP ports 2379, 2380, 6443, 8091, 10250, 10257 and 10259 open between cluster nodes + : + + TCP ports 2379, 2380, 6443, 8091, 10250, 10257, 10259 and 51820 open between cluster nodes + } +
  • } + {installerData && installerData.spec.antrea && installerData.spec.antrea.version && +
  • + UDP port 6081 open between cluster nodes +
  • } + {installerData && installerData.spec.rook && installerData.spec.rook.version && +
  • + TCP port 9090 open between cluster nodes +
  • } @@ -234,8 +265,12 @@ cat install.sh | sudo bash -s airgap

    {installerData.spec.kubernetes && } + {installerData.spec.flannel && + } {installerData.spec.weave && } + {installerData.spec.antrea && + } {installerData.spec.contour && } {installerData.spec.rook && @@ -271,7 +306,9 @@ cat install.sh | sudo bash -s airgap {installerData.spec.sonobuoy && } {installerData.spec.localPathProvisioner && - } + } + {installerData.spec.aws && + } } {installerData && diff --git a/src/components/AppVersionCard.js b/src/components/AppVersionCard.js index ff1bb7dd..78e895a8 100644 --- a/src/components/AppVersionCard.js +++ b/src/components/AppVersionCard.js @@ -9,8 +9,6 @@ export default class AppVersionCard extends React.Component { return "KOTS"; } else if (name === "openebs") { return "OpenEBS"; - } else if (name === "longhorn") { - return "Longhorn"; } else if (name === "certManager") { return "Cert manager" } else if (name === "metricsServer") { diff --git a/src/components/Kurlsh.js b/src/components/Kurlsh.js index 1b0172ad..bdd0fe8b 100644 --- a/src/components/Kurlsh.js +++ b/src/components/Kurlsh.js @@ -3,13 +3,13 @@ import { Link } from "@reach/router"; import ReactTooltip from "react-tooltip"; import json2yaml from "json2yaml"; -import Select from "react-select"; import isEmpty from "lodash/isEmpty"; import find from "lodash/find"; import semver from "semver"; import CodeSnippet from "./shared/CodeSnippet"; import Loader from "./shared/Loader"; +import AddOnWrapper from "./shared/AddOnWrapper"; import OptionWrapper from "./shared/OptionWrapper"; import ConfirmSelectionModal from "./modals/ConfirmSelectionModal"; import { injectYamlOpenebsComment } from "../utils/kurl-yaml"; @@ -20,13 +20,9 @@ import _ from "lodash"; const NIL_VERSIONS = { kubernetes: { version: "None" }, - rke2: { version: "None" }, - k3s: { version: "None" }, - weave: { version: "None" }, - antrea: { version: "None" }, + flannel: { version: "None" }, contour: { version: "None" }, rook: { version: "None" }, - docker: { version: "None" }, prometheus: { version: "None" }, registry: { version: "None" }, containerd: { version: "None" }, @@ -36,108 +32,55 @@ const NIL_VERSIONS = { fluentd: { version: "None" }, minio: { version: "None" }, openebs: { version: "None" }, - longhorn: { version: "None" }, collectd: { version: "None" }, metricsServer: { version: "None" }, certManager: { version: "None" }, sonobuoy: { version: "None" }, goldpinger: { version: "None" }, - aws: { version: "None" }, } -const hasAdvancedOptions = ["kubernetes", "weave", "antrea", "contour", "rook", "registry", "docker", "velero", "kotsadm", "ekco", "fluentd", "minio", "openebs", "longhorn", "prometheus", "aws"]; +const hasAdvancedOptions = ["kubernetes", "flannel", "contour", "rook", "registry", "velero", "kotsadm", "ekco", "fluentd", "minio", "openebs", "prometheus"]; function versionToState(version) { return { version }; } +// replace problematic versions that do not sort because of semver pre-release +const replaceVersions = { + "rook": {"1.0.4": "1.0.4-0.0.0"}, + "prometheus": {"0.46.0": "0.46.0-0.0.0"}, +}; + class Kurlsh extends React.Component { constructor(props) { super(props); const { supportedVersions } = props; - let kubernetesVersions = this.addDotXVersions(supportedVersions.kubernetes.map(versionToState)); - kubernetesVersions = this.prepareVersions(kubernetesVersions) - - let rke2Versions = this.addDotXVersions(supportedVersions.rke2.map(versionToState)); - rke2Versions = this.prepareVersions(rke2Versions); - - let k3sVersions = this.addDotXVersions(supportedVersions.k3s.map(versionToState)); - k3sVersions = this.prepareVersions(k3sVersions); - - let contourVersions = this.addDotXVersions(supportedVersions.contour.map(versionToState)); - contourVersions = this.prepareVersions(contourVersions); - - let weaveVersions = this.addDotXVersions(supportedVersions.weave.map(versionToState)); - weaveVersions = this.prepareVersions(weaveVersions); - - let antreaVersions = this.addDotXVersions(supportedVersions.antrea.map(versionToState)); - antreaVersions = this.prepareVersions(antreaVersions); - - let rookVersions = this.addDotXVersions(supportedVersions.rook.map(versionToState)); - rookVersions = this.prepareVersions(rookVersions); - - let dockerVersions = this.addDotXVersions(supportedVersions.docker.map(versionToState)); - dockerVersions = this.prepareVersions(dockerVersions); - - let prometheusVersions = this.addDotXVersions(supportedVersions.prometheus.map(versionToState)); - prometheusVersions = this.prepareVersions(prometheusVersions); - - let registryVersions = this.addDotXVersions(supportedVersions.registry.map(versionToState)); - registryVersions = this.prepareVersions(registryVersions); - - let containerdVersions = this.addDotXVersions(supportedVersions.containerd.map(versionToState)); - containerdVersions = this.prepareVersions(containerdVersions); - - let veleroVersions = this.addDotXVersions(supportedVersions.velero.map(versionToState)); - veleroVersions = this.prepareVersions(veleroVersions); - - let kotsadmVersions = this.addDotXVersions(supportedVersions.kotsadm.map(versionToState)); - kotsadmVersions = this.prepareVersions(kotsadmVersions); - - let ekcoVersions = this.addDotXVersions(supportedVersions.ekco.map(versionToState)); - ekcoVersions = this.prepareVersions(ekcoVersions); - - let fluentdVersions = this.addDotXVersions(supportedVersions.fluentd.map(versionToState)); - fluentdVersions = this.prepareVersions(fluentdVersions); - - let minioVersions = this.addDotXVersions(supportedVersions.minio.map(versionToState)); - minioVersions = this.prepareVersions(minioVersions); - - let openebsVersions = this.addDotXVersions(supportedVersions.openebs.map(versionToState)); - openebsVersions = this.prepareVersions(openebsVersions); - - let longhornVersions = this.addDotXVersions(supportedVersions.longhorn.map(versionToState)); - longhornVersions = this.prepareVersions(longhornVersions); - - let collectdVersions = this.addDotXVersions(supportedVersions.collectd.map(versionToState)); - collectdVersions = this.prepareVersions(collectdVersions); - - let metricsServerVersions = this.addDotXVersions(supportedVersions["metrics-server"].map(versionToState)); - metricsServerVersions = this.prepareVersions(metricsServerVersions); - - let certManagerVersions = this.addDotXVersions(supportedVersions["cert-manager"].map(versionToState)); - certManagerVersions = this.prepareVersions(certManagerVersions); - - let sonobuoyVersions = this.addDotXVersions(supportedVersions["sonobuoy"].map(versionToState)); - sonobuoyVersions = this.prepareVersions(sonobuoyVersions); - - let goldpingerVersions = this.addDotXVersions(supportedVersions["goldpinger"].map(versionToState)); - goldpingerVersions = this.prepareVersions(goldpingerVersions); - - let awsVersions = this.addDotXVersions(supportedVersions["aws"].map(versionToState)); - awsVersions = this.prepareVersions(awsVersions); + const kubernetesVersions = this.prepareVersions("kubernetes", supportedVersions.kubernetes); + const contourVersions = this.prepareVersions("contour", supportedVersions.contour); + const flannelVersions = this.prepareVersions("flannel", supportedVersions.flannel); + const rookVersions = this.prepareVersions("rook", supportedVersions.rook); + const prometheusVersions = this.prepareVersions("prometheus", supportedVersions.prometheus); + const registryVersions = this.prepareVersions("registry", supportedVersions.registry); + const containerdVersions = this.prepareVersions("containerd", supportedVersions.containerd); + const veleroVersions = this.prepareVersions("velero", supportedVersions.velero); + const kotsadmVersions = this.prepareVersions("kotsadm", supportedVersions.kotsadm); + const ekcoVersions = this.prepareVersions("ekco", supportedVersions.ekco); + const fluentdVersions = this.prepareVersions("fluentd", supportedVersions.fluentd); + const minioVersions = this.prepareVersions("minio", supportedVersions.minio); + const openebsVersions = this.prepareVersions("openebs", supportedVersions.openebs); + const collectdVersions = this.prepareVersions("collectd", supportedVersions.collectd); + const metricsServerVersions = this.prepareVersions("metrics-server", supportedVersions["metrics-server"]); + const certManagerVersions = this.prepareVersions("cert-manager", supportedVersions["cert-manager"]); + const sonobuoyVersions = this.prepareVersions("sonobuoy", supportedVersions.sonobuoy); + const goldpingerVersions = this.prepareVersions("goldpinger", supportedVersions.goldpinger); this.state = { versions: { kubernetes: kubernetesVersions, - rke2: rke2Versions, - k3s: k3sVersions, - weave: weaveVersions, - antrea: antreaVersions, + flannel: flannelVersions, contour: contourVersions, rook: rookVersions, - docker: dockerVersions, prometheus: prometheusVersions, registry: registryVersions, containerd: containerdVersions, @@ -147,74 +90,56 @@ class Kurlsh extends React.Component { fluentd: fluentdVersions, minio: minioVersions, openebs: openebsVersions, - longhorn: longhornVersions, collectd: collectdVersions, metricsServer: metricsServerVersions, certManager: certManagerVersions, sonobuoy: sonobuoyVersions, goldpinger: goldpingerVersions, - aws: awsVersions, }, selectedVersions: NIL_VERSIONS, installerSha: "", showAdvancedOptions: { "kubernetes": false, - "rke2": false, - "k3s": false, - "weave": false, - "antrea": false, + "flannel": false, "contour": false, "rook": false, "prometheus": false, "registry": false, - "docker": false, "velero": false, "kotsadm": false, "ekco": false, "fluentd": false, "minio": false, "openebs": false, - "longhorn": false, "metricsServer": false, "certManager": false, "sonobuoy": false, "goldpinger": false, - "aws": false, }, advancedOptions: { kubernetes: {}, - rke2: {}, - k3s: {}, - weave: {}, - antrea: {}, + flannel: {}, contour: {}, rook: {}, registry: {}, - docker: {}, velero: {}, kotsadm: {}, ekco: {}, fluentd: {}, minio: {}, openebs: {}, - longhorn: {}, collectd: {}, metricsServer: {}, certManager: {}, sonobuoy: {}, goldpinger: {}, prometheus: {}, - aws: {}, }, isAddOnChecked: { kubernetes: false, - rke2: false, - k3s: false, - weave: false, - antrea: false, + flannel: false, contour: false, rook: false, - docker: false, prometheus: false, registry: false, containerd: false, @@ -224,15 +149,12 @@ class Kurlsh extends React.Component { fluentd: false, minio: false, openebs: false, - longhorn: false, collectd: false, metricsServer: false, certManager: false, sonobuoy: false, goldpinger: false, - aws: false, }, - isEditorLoading: false, optionDefaults: {}, installerErrMsg: "", displayConfirmSelectionModal: false, @@ -240,12 +162,46 @@ class Kurlsh extends React.Component { }; } - prepareVersions = versions => { - // the list of versions returned by the api has, as it first item, a version called - // "latest", the item immediately after it is the actual version we consider to be - // the latest. we save it here so we can remember where we need to insert it after. - let latest = versions[1].version; + prepareVersions = (addon, versions) => { + const stateVersions = versions ? versions.map(versionToState) : []; + const replacedVersions = this.replaceVersions(addon, stateVersions); + const latest = this.findLatestVersion(replacedVersions); + const dotXVersions = this.addDotXVersions(replacedVersions); + const sortedVersions = this.sortVersions(dotXVersions, latest); + return this.unreplaceVersions(addon, sortedVersions); + } + replaceVersions = (addon, versions) => { + let next = _.cloneDeep(versions); + if (addon in replaceVersions) { + Object.keys(replaceVersions[addon]).forEach((k) => { + next = next.map(function(version) { + if (version.version === k) { + version.version = replaceVersions[addon][k]; + } + return version; + }); + }); + } + return next; + } + + unreplaceVersions = (addon, versions) => { + let next = _.cloneDeep(versions); + if (addon in replaceVersions) { + Object.keys(replaceVersions[addon]).forEach((k) => { + next = next.map(function(version) { + if (version.version === replaceVersions[addon][k]) { + version.version = k; + } + return version; + }); + }); + } + return next; + } + + sortVersions = (versions, latest) => { // remove the "latest" version from the list and sort the resulting array. we will // re-insert "latest" after sorting the array as it has to be the option just before // the "actual" latest version. @@ -265,6 +221,13 @@ class Kurlsh extends React.Component { return result; } + findLatestVersion = versions => { + // the list of versions returned by the api has, as it first item, a version called + // "latest", the item immediately after it is the actual version we consider to be + // the latest. we save it here so we can remember where we need to insert it after. + return versions && versions.length > 1 ? versions[1].version : undefined; + } + // compareVersions do the best to sort out versions returned by the api. this function // only considers versions that ressembles the semantic version format, if the version // does not look like a semantic version this function simply returns 0. @@ -279,9 +242,15 @@ class Kurlsh extends React.Component { yver = yver.replace(".x", ".99999"); } - if (semver.valid(xver) === null || semver.valid(yver) === null) { + if (!semver.valid(xver) || !semver.valid(yver)) { return 0; } + if (!xver.includes("-")) { + xver = `${xver}-0`; + } + if (!yver.includes("-")) { + yver = `${yver}-0`; + } return semver.gt(yver, xver) ? 1 : -1; } @@ -354,7 +323,8 @@ class Kurlsh extends React.Component { const { selectedVersions, advancedOptions, - optionDefaults + optionDefaults, + isAddOnChecked, } = this.state; const generatedInstaller = { @@ -380,7 +350,7 @@ class Kurlsh extends React.Component { const options = this.generateAdvancedOptionsForYaml(advancedOptions, optionDefaults); - if (selectedVersions.kubernetes.version !== "None") { + if (isAddOnChecked.kubernetes) { const diff = getDiff(optionDefaults["kubernetes"], options.kubernetes); generatedInstaller.spec.kubernetes = { @@ -395,66 +365,22 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.rke2.version !== "None") { - const diff = getDiff(optionDefaults["rke2"], options.rke2); - - generatedInstaller.spec.rke2 = { - version: selectedVersions.rke2.version - }; - - if (Object.keys(diff).length) { - generatedInstaller.spec.rke2 = { - ...generatedInstaller.spec.rke2, - ...diff - }; - } - } - - if (selectedVersions.k3s.version !== "None") { - const diff = getDiff(optionDefaults["k3s"], options.k3s); - - generatedInstaller.spec.k3s = { - version: selectedVersions.k3s.version - }; - - if (Object.keys(diff).length) { - generatedInstaller.spec.k3s = { - ...generatedInstaller.spec.k3s, - ...diff - }; - } - } - - if (selectedVersions.weave.version !== "None") { - const diff = getDiff(optionDefaults["weave"], options.weave); + if (isAddOnChecked.flannel) { + const diff = getDiff(optionDefaults["flannel"], options.flannel); - generatedInstaller.spec.weave = { - version: selectedVersions.weave.version + generatedInstaller.spec.flannel = { + version: selectedVersions.flannel.version }; if (Object.keys(diff).length) { - generatedInstaller.spec.weave = { - ...generatedInstaller.spec.weave, + generatedInstaller.spec.flannel = { + ...generatedInstaller.spec.flannel, ...diff }; } } - if (selectedVersions.antrea.version !== "None") { - const diff = getDiff(optionDefaults["antrea"], options.antrea); - generatedInstaller.spec.antrea = { - version: selectedVersions.antrea.version - }; - - if (Object.keys(diff).length) { - generatedInstaller.spec.antrea = { - ...generatedInstaller.spec.antrea, - ...diff - }; - } - } - - if (selectedVersions.rook.version !== "None") { + if (isAddOnChecked.rook) { const diff = getDiff(optionDefaults["rook"], options.rook); generatedInstaller.spec.rook = { version: selectedVersions.rook.version @@ -468,7 +394,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.contour.version !== "None") { + if (isAddOnChecked.contour) { const diff = getDiff(optionDefaults["contour"], options.contour); generatedInstaller.spec.contour = { version: selectedVersions.contour.version @@ -482,21 +408,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.docker.version !== "None") { - const diff = getDiff(optionDefaults["docker"], options.docker); - generatedInstaller.spec.docker = { - version: selectedVersions.docker.version - }; - - if (Object.keys(diff).length) { - generatedInstaller.spec.docker = { - ...generatedInstaller.spec.docker, - ...diff - }; - } - } - - if (selectedVersions.prometheus.version !== "None") { + if (isAddOnChecked.prometheus) { const diff = getDiff(optionDefaults["prometheus"], options.prometheus); generatedInstaller.spec.prometheus = { version: selectedVersions.prometheus.version @@ -510,7 +422,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.registry.version !== "None") { + if (isAddOnChecked.registry) { const diff = getDiff(optionDefaults["registry"], options.registry); generatedInstaller.spec.registry = { version: selectedVersions.registry.version @@ -524,13 +436,13 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.containerd.version !== "None") { + if (isAddOnChecked.containerd) { generatedInstaller.spec.containerd = { version: selectedVersions.containerd.version }; } - if (selectedVersions.velero.version !== "None") { + if (isAddOnChecked.velero) { const diff = getDiff(optionDefaults["velero"], options.velero); generatedInstaller.spec.velero = { version: selectedVersions.velero.version @@ -544,7 +456,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.kotsadm.version !== "None") { + if (isAddOnChecked.kotsadm) { const diff = getDiff(optionDefaults["kotsadm"], options.kotsadm); generatedInstaller.spec.kotsadm = { version: selectedVersions.kotsadm.version @@ -558,7 +470,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.ekco.version !== "None") { + if (isAddOnChecked.ekco) { const diff = getDiff(optionDefaults["ekco"], options.ekco); generatedInstaller.spec.ekco = { version: selectedVersions.ekco.version @@ -572,7 +484,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.fluentd.version !== "None") { + if (isAddOnChecked.fluentd) { const diff = getDiff(optionDefaults["fluentd"], options.fluentd); generatedInstaller.spec.fluentd = { version: selectedVersions.fluentd.version @@ -586,7 +498,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.minio.version !== "None") { + if (isAddOnChecked.minio) { const diff = getDiff(optionDefaults["minio"], options.minio); generatedInstaller.spec.minio = { version: selectedVersions.minio.version @@ -600,7 +512,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.openebs.version !== "None") { + if (isAddOnChecked.openebs) { const diff = getDiff(optionDefaults["openebs"], options.openebs); generatedInstaller.spec.openebs = { version: selectedVersions.openebs.version @@ -614,21 +526,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.longhorn.version !== "None") { - const diff = getDiff(optionDefaults["longhorn"], options.longhorn); - generatedInstaller.spec.longhorn = { - version: selectedVersions.longhorn.version - }; - - if (Object.keys(diff).length) { - generatedInstaller.spec.longhorn = { - ...generatedInstaller.spec.longhorn, - ...diff - }; - } - } - - if (selectedVersions.collectd.version !== "None") { + if (isAddOnChecked.collectd) { const diff = getDiff(optionDefaults["collectd"], options.collectd); generatedInstaller.spec.collectd = { version: selectedVersions.collectd.version @@ -642,7 +540,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.metricsServer.version !== "None") { + if (isAddOnChecked.metricsServer) { const diff = getDiff(optionDefaults["metricsServer"], options.metricsServer); generatedInstaller.spec.metricsServer = { version: selectedVersions.metricsServer.version @@ -656,7 +554,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.certManager.version !== "None") { + if (isAddOnChecked.certManager) { const diff = getDiff(optionDefaults["certManager"], options.certManager); generatedInstaller.spec.certManager = { version: selectedVersions.certManager.version @@ -670,7 +568,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.sonobuoy.version !== "None") { + if (isAddOnChecked.sonobuoy) { const diff = getDiff(optionDefaults["sonobuoy"], options.sonobuoy); generatedInstaller.spec.sonobuoy = { version: selectedVersions.sonobuoy.version @@ -684,7 +582,7 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.goldpinger.version !== "None") { + if (isAddOnChecked.goldpinger) { const diff = getDiff(optionDefaults["goldpinger"], options.goldpinger); generatedInstaller.spec.goldpinger = { version: selectedVersions.goldpinger.version @@ -698,20 +596,6 @@ class Kurlsh extends React.Component { } } - if (selectedVersions.aws.version !== "None") { - const diff = getDiff(optionDefaults["aws"], options.aws); - generatedInstaller.spec.aws = { - version: selectedVersions.aws.version - }; - - if (Object.keys(diff).length) { - generatedInstaller.spec.aws = { - ...generatedInstaller.spec.aws, - ...diff - }; - } - } - let renderedYaml = json2yaml.stringify(generatedInstaller).replace("---\n", "").replace(/^ {2}/gm, ""); if (sha === "latest") { @@ -732,28 +616,18 @@ class Kurlsh extends React.Component { } onVersionChange = name => value => { - if (name === "kubernetes" || name === "rke2" || name === "k3s") { + if (name === "kubernetes") { if (value.version === "None") { // can't be deselected, deselection happens when changing between them return; } } - if (name === "containerd" && value.version !== "None" && this.state.selectedVersions.docker.version !== "None") { - this.checkIncompatibleSelection({ containerd: value }); - } else if (name === "docker" && value.version !== "None" && this.state.selectedVersions.containerd.version !== "None") { - this.checkIncompatibleSelection({ docker: value }); - } else if (name === "antrea" && value.version !== "None" && this.state.selectedVersions.weave.version !== "None") { - this.checkIncompatibleSelection({ antrea: value }); - } else if (name === "weave" && value.version !== "None" && this.state.selectedVersions.antrea.version !== "None") { - this.checkIncompatibleSelection({ weave: value }); - } else { - this.setState({ selectedVersions: { ...this.state.selectedVersions, [name]: value } }, () => { - if (value.version === "None") { - this.setState({ isAddOnChecked: { ...this.state.isAddOnChecked, [name]: !this.state.isAddOnChecked[name] } }) - } - this.postToKurlInstaller(this.getYaml(this.state.installerSha)); - }) - } + this.setState({ selectedVersions: { ...this.state.selectedVersions, [name]: value } }, () => { + if (value.version === "None") { + this.setState({ isAddOnChecked: { ...this.state.isAddOnChecked, [name]: !this.state.isAddOnChecked[name] } }) + } + this.postToKurlInstaller(this.getYaml(this.state.installerSha)); + }) } handleIsAddOnSelected = (name, e) => { @@ -763,41 +637,44 @@ class Kurlsh extends React.Component { !e.target.classList.contains("css-tlfecz-indicatorContainer") && !e.target.classList.contains("css-1gtu0rj-indicatorContainer") && !e.target.classList.contains("css-1g48xl4-IndicatorsContainer") && !e.target.classList.contains("AdvancedOptions--wrapper") && !e.target.classList.contains("Option--wrapper")) { - if (name === "kubernetes" || name === "rke2" || name === "k3s") { + if (name === "kubernetes") { if (this.state.isAddOnChecked[name]) { // can't be deselected, deselection happens when changing between them return; } } + let nextIsAddOnChecked = { + ...this.state.isAddOnChecked, + }; + if (name === "kubernetes") { + nextIsAddOnChecked = { + ...nextIsAddOnChecked, + kubernetes: false, + }; + } this.setState({ isAddOnChecked: { - ...this.state.isAddOnChecked, - kubernetes: false, - rke2: false, - k3s: false, + ...nextIsAddOnChecked, [name]: !this.state.isAddOnChecked[name], - } + }, }, () => { if (this.state.isAddOnChecked[name]) { + let nextSelectedVersions = { + ...this.state.selectedVersions, + }; if (name === "kubernetes") { - this.setState({ selectedVersions: NIL_VERSIONS}, () => this.getKurlInstaller("latest")); - } else if (name === "rke2") { - this.setState({ selectedVersions: NIL_VERSIONS}, () => this.getKurlInstaller("rke2")); - } else if (name === "k3s") { - this.setState({ selectedVersions: NIL_VERSIONS}, () => this.getKurlInstaller("k3s")); - } else if (name === "containerd" && this.state.selectedVersions.docker.version !== "None") { - this.checkIncompatibleSelection({ containerd: { version: "latest" } }); - } else if (name === "docker" && this.state.selectedVersions.containerd.version !== "None") { - this.checkIncompatibleSelection({ docker: { version: "latest" } }); - } else if (name === "weave" && this.state.selectedVersions.antrea.version !== "None") { - this.checkIncompatibleSelection({ weave: { version: "latest" } }); - } else if (name === "antrea" && this.state.selectedVersions.weave.version !== "None") { - this.checkIncompatibleSelection({ antrea: { version: "latest" } }); - } else { - this.setState({ selectedVersions: { ...this.state.selectedVersions, [name]: { version: "latest" } } }, () => { - this.postToKurlInstaller(this.getYaml(this.state.installerSha)); - }); + return; // cannot be deselected, it is the only option } + + let selectedVersion = this.state.versions[name][0].version; + if (selectedVersion === "latest" && name !== "ekco") { + selectedVersion = this.state.versions[name][1].version; + } + + this.setState({ selectedVersions: { ...nextSelectedVersions, [name]: { version: selectedVersion } } }, () => { + this.postToKurlInstaller(this.getYaml(this.state.installerSha)); + }); + } else { this.setState({ selectedVersions: { ...this.state.selectedVersions, [name]: { version: "None" } } }, () => { this.postToKurlInstaller(this.getYaml(this.state.installerSha)); @@ -827,8 +704,11 @@ class Kurlsh extends React.Component { } else if (version.endsWith(".x")) { const versionIndex = this.state.versions[name].findIndex((element) => element.version === version); if (this.state.versions[name].length > versionIndex) { // if there is a member of the array after the one specified - const next = this.state.versions[name][versionIndex+1] - version = `${version} (${next.version})` + let next = this.state.versions[name][versionIndex+1]; + if (next.version === "latest") { // if the next version is "latest" + next = this.state.versions[name][versionIndex+2]; + } + version = `${version} (${next.version})`; } } return version; @@ -836,7 +716,9 @@ class Kurlsh extends React.Component { postToKurlInstaller = async (yaml) => { this.setState({ installerErrMsg: "" }) - const url = `${process.env.KURL_INSTALLER_URL}` + let parsedURL = new URL(process.env.KURL_INSTALLER_URL); + parsedURL.searchParams.append('austere', true); + const url = parsedURL.toString(); try { const response = await fetch(url, { method: "POST", @@ -849,10 +731,14 @@ class Kurlsh extends React.Component { const res = await response.text(); const splittedRes = res.split("/"); const installerSha = splittedRes[splittedRes.length - 1]; - this.setState({ installerSha }); + this.setState({ installerErrMsg: "", installerSha }); } else { const body = await response.json(); - this.setState({ installerErrMsg: body.error.message || "something went wrong" }); + if (Array.isArray(body)) { + this.setState({ installerErrMsg: body[0].message || "something went wrong" }); + } else { + this.setState({ installerErrMsg: body.error.message || "something went wrong" }); + } } } catch (err) { this.setState({ installerErrMsg: `${err}` }); @@ -909,38 +795,9 @@ class Kurlsh extends React.Component { } handleOptionChange = (path, currentTarget, type) => { - let addOnData = {} let elementToFocus; const [field, key] = path.split('.'); - - if (currentTarget.type === "checkbox") { - if (type === "boolean") { - addOnData = { - inputValue: currentTarget.checked ? true : false, - isChecked: currentTarget.checked - } - } else { - if (type === "string") { - addOnData = { - inputValue: "", - isChecked: currentTarget.checked, - } - } else { - addOnData = { - inputValue: 0, - isChecked: currentTarget.checked, - } - } - } - } else if (currentTarget.type === "number") { - addOnData = { - inputValue: parseInt(currentTarget.value, 10) || 0 - } - } else { - addOnData = { - inputValue: currentTarget.value - } - } + const addOnData = this.addOnDataFromInput(currentTarget, type); this.setState({ advancedOptions: { @@ -966,6 +823,56 @@ class Kurlsh extends React.Component { }); } + addOnDataFromInput(targetInput, fieldType) { + let addOnData = {} + + if (targetInput.type === "checkbox") { + if (fieldType === "boolean") { + addOnData = { + inputValue: targetInput.checked ? true : false, + isChecked: targetInput.checked + } + } else { + if (fieldType === "string") { + addOnData = { + inputValue: "", + isChecked: targetInput.checked, + } + } else if (fieldType === "array[string]") { + addOnData = { + inputValue: [], + isChecked: targetInput.checked, + } + } else { + addOnData = { + inputValue: 0, + isChecked: targetInput.checked, + } + } + } + } else if (targetInput.type === "number") { + addOnData = { + inputValue: parseInt(targetInput.value, 10) || 0 + } + } else if (targetInput.type === "text") { + if (fieldType === "array[string]") { + addOnData = { + inputValue: targetInput.value.split(",") + } + } else { + addOnData = { + inputValue: targetInput.value + } + } + } else { + addOnData = { + inputValue: targetInput.value + } + } + + return addOnData; + } + renderMonacoEditor = () => { import("monaco-editor").then(monaco => { window.monacoEditor = monaco.editor.create(document.getElementById("monaco"), { @@ -1068,12 +975,12 @@ class Kurlsh extends React.Component { - {option.type === "string" || option.type === "number" ? + {option.type === "string" || option.type === "array[string]" || option.type === "number" ?
    this.handleOptionChange(`${addOn}.${data.flag}`, e.currentTarget, option.type)} disabled={!currentOption || (currentOption && !currentOption.isChecked)} value={currentOption ? currentOption.inputValue : ""} @@ -1119,28 +1026,29 @@ class Kurlsh extends React.Component { // add versions like "1.19.x" to the list of installable versions addDotXVersions = (actualVersions) => { + let versions = _.cloneDeep(actualVersions); // make a copy // get a list of the distinct minor versions const minorVersionsRegex = /(^[0-9]+\.[0-9]+)\.[0-9]+/; let minorVersions = []; - actualVersions.forEach(v => { + versions.forEach(v => { const matches = v.version.match(minorVersionsRegex); if (matches && matches.length > 1 && !minorVersions.includes(matches[1])) { minorVersions.push(matches[1]); } }) - // for each minor version, find the first version in the actualVersions array that matches + // for each minor version, find the first version in the versions array that matches // and insert `1.minor.x` before it minorVersions.forEach(mv => { - const isMatch = actualVersions.find(av => av.version.startsWith(mv+".")); + const isMatch = versions.find(av => av.version.startsWith(mv+".")); if (!!isMatch) { - actualVersions.splice(actualVersions.indexOf(isMatch), 0, {version: mv+".x"}); + versions.splice(versions.indexOf(isMatch), 0, {version: mv+".x"}); } }) - return actualVersions + return versions; } render() { - const { versions, selectedVersions, installerSha, showAdvancedOptions, isEditorLoading, installerErrMsg } = this.state; + const { versions, selectedVersions, installerSha, showAdvancedOptions, isEditorLoading, installerErrMsg, isAddOnChecked } = this.state; const { isMobile } = this.props; const installCommand = `curl ${process.env.API_URL}/${installerSha} | sudo bash`; @@ -1168,870 +1076,299 @@ class Kurlsh extends React.Component { Select add-ons
    Distribution -
    this.handleIsAddOnSelected("kubernetes", e)}> -
    -
    - - -
    -
    Kubernetes (Kubeadm)
    -
    - {!this.state.isAddOnChecked["kubernetes"] ? "Version None" : "Version"} - - -
    -
    RKE2 beta
    -
    - {!this.state.isAddOnChecked["rke2"] ? "Version None" : "Version"} - - -
    -
    K3s beta
    -
    - {!this.state.isAddOnChecked["k3s"] ? "Version None" : "Version"} - - -
    -
    Docker
    -
    - {!this.state.isAddOnChecked["docker"] ? "Version None" : "Version"} - - -
    -
    Containerd
    -
    - {!this.state.isAddOnChecked["containerd"] ? "Version None" : "Version"} - - -
    -
    Antrea
    -
    - {!this.state.isAddOnChecked["antrea"] ? "Version None" : "Version"} - - -
    -
    Weave
    -
    - {!this.state.isAddOnChecked["weave"] ? "Version None" : "Version"} - - -
    -
    Contour
    -
    - {!this.state.isAddOnChecked["contour"] ? "Version None" : "Version"} - - -
    -
    EKCO
    -
    - {!this.state.isAddOnChecked["ekco"] ? "Version None" : "Version"} - - -
    -
    Sonobuoy
    -
    -
    - {!this.state.isAddOnChecked["sonobuoy"] ? "Version None" : "Version"} - - -
    -
    Fluentd
    -
    - {!this.state.isAddOnChecked["fluentd"] ? "Version None" : "Version"} - - -
    -
    KOTS
    -
    - {!this.state.isAddOnChecked["kotsadm"] ? "Version None" : "Version"} - - -
    -
    Minio
    -
    - {!this.state.isAddOnChecked["minio"] ? "Version None" : "Version"} - - -
    -
    Rook
    -
    -
    - {!this.state.isAddOnChecked["rook"] ? "Version None" : "Version"} - - -
    -
    Longhorn
    -
    - {!this.state.isAddOnChecked["longhorn"] ? "Version None" : "Version"} - - -
    -
    openEBS
    -
    - {!this.state.isAddOnChecked["openebs"] ? "Version None" : "Version"} - - -
    -
    Prometheus
    -
    - {!this.state.isAddOnChecked["prometheus"] ? "Version None" : "Version"} - - -
    -
    Collectd
    -
    - {!this.state.isAddOnChecked["collectd"] ? "Version None" : "Version"} - - -
    -
    Metrics-server
    -
    - {!this.state.isAddOnChecked["metricsServer"] ? "Version None" : "Version"} - - -
    -
    Goldpinger
    -
    - {!this.state.isAddOnChecked["goldpinger"] ? "Version None" : "Version"} - - -
    -
    Cert manager
    -
    - {!this.state.isAddOnChecked["certManager"] ? "Version None" : "Version"} - - -
    -
    Docker Registry
    -
    - {!this.state.isAddOnChecked["registry"] ? "Version None" : "Version"} - - -
    -
    Velero
    -
    -
    - {!this.state.isAddOnChecked["velero"] ? "Version None" : "Version"} - - -
    -
    AWS beta
    -
    -
    - {!this.state.isAddOnChecked["aws"] ? "Version None" : "Version"} - + +
    +
    {addOnTitle} { isBeta && beta } { isDeprecated && deprecated }
    +
    + {!isAddOnChecked ? "Version None" : "Version"} +