diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..a1da8d05 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +*.yml linguist-detectable=true +*.yml linguist-language=YAML +*.qmd linguist-language=Markdown +*.md linguist-detectable +*.qmd linguist-detectable diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 777baeb2..2f28369a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,9 +1,19 @@ # format per https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#about-code-owners -* @colearendt @atheriel +* @rstudio/infraops @rstudio/platform-cloud # package-manager resources -/charts/rstudio-pm/* @rstudio/ppm +/charts/rstudio-pm/** @rstudio/ppm +/ci/rstudio-pm/** @rstudio/ppm # connect resources -/charts/rstudio-connect/* @aronatkins @dbkegley @christierney @zackverham -/examples/connect/* @aronatkins @dbkegley @christierney @zackverham +/charts/rstudio-connect/** @aronatkins @dbkegley @christierney @zackverham +/ci/rstudio-connect/** @aronatkins @dbkegley @christierney @zackverham +/examples/connect/** @aronatkins @dbkegley @christierney @zackverham + +# posit-chronicle resources +/charts/posit-chronicle/** @matt-urbina @markrtucker @t-margheim +/ci/posit-chronicle/** @matt-urbina @markrtucker @t-margheim + +# rstudio-workbench resources +/charts/rstudio-workbench/** @GCrev @zachhannum +/ci/rstudio-workbench/** @GCrev @zachhannum diff --git a/.github/workflows/chart-doc.yaml b/.github/workflows/chart-doc.yaml index 249220fe..efd09880 100644 --- a/.github/workflows/chart-doc.yaml +++ b/.github/workflows/chart-doc.yaml @@ -9,30 +9,29 @@ jobs: name: helm-docs steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - uses: r-lib/actions/pr-fetch@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Set up Helm - uses: azure/setup-helm@v3 + uses: azure/setup-helm@v4.2.0 with: version: v3.6.3 - - name: Install helm-docs - env: - version: 1.5.0 - run: | - echo "Installing helm-docs version $version" - curl -L -o helm-docs.tar.gz https://github.com/norwoodj/helm-docs/releases/download/v${version}/helm-docs_${version}_Linux_x86_64.tar.gz - tar -xzvf helm-docs.tar.gz helm-docs - rm -rf helm-docs.tar.gz + - name: install Just + uses: extractions/setup-just@v2 - - name: Run helm-docs - run: | - ./helm-docs --chart-search-root=charts --template-files=README.md.gotmpl --template-files=./_templates.gotmpl - ./helm-docs --chart-search-root=other-charts --template-files=README.md.gotmpl --template-files=./_templates.gotmpl + - name: Install Quarto + uses: quarto-dev/quarto-actions/setup@v2 + with: + version: pre-release + + - name: Render Quarto Project + uses: quarto-dev/quarto-actions/render@v2 + env: + HELM_DOCS_VERSION: 1.13.1 - name: Commit results run: | @@ -45,30 +44,53 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: Notify Slack of chart documentation failure + if: failure() + uses: slackapi/slack-github-action@v1.27.0 + with: + payload-delimiter: "_" + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Chart Documentation failed, please check the logs. ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + rbac: runs-on: ubuntu-latest name: rbac needs: document steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - uses: r-lib/actions/pr-fetch@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Set up Helm - uses: azure/setup-helm@v3 + uses: azure/setup-helm@v4.2.0 with: version: v3.6.3 + - name: Add rstudio helm repo + run: helm repo add rstudio https://helm.rstudio.com + + - name: install Just + uses: extractions/setup-just@v2 + - name: Compute and update dependent files run: | - set -xe - cd ./charts/rstudio-launcher-rbac && helm dependency build && cd - - helm template -n rstudio rstudio-launcher-rbac ./charts/rstudio-launcher-rbac --set removeNamespaceReferences=true > examples/rbac/rstudio-launcher-rbac.yaml - CHART_VERSION=$(helm show chart ./charts/rstudio-launcher-rbac | grep '^version' | cut -d ' ' -f 2) - cp examples/rbac/rstudio-launcher-rbac.yaml examples/rbac/rstudio-launcher-rbac-${CHART_VERSION}.yaml + just rbac - name: Commit results run: | @@ -81,3 +103,24 @@ jobs: - uses: r-lib/actions/pr-push@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Notify Slack of chart documentation (rbac) failure + if: failure() + uses: slackapi/slack-github-action@v1.27.0 + with: + payload-delimiter: "_" + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Chart Documentation (RBAC) failed, please check the logs. ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK diff --git a/.github/workflows/chart-rebuild.yaml b/.github/workflows/chart-rebuild.yaml index dc18cefe..1d3fba9c 100644 --- a/.github/workflows/chart-rebuild.yaml +++ b/.github/workflows/chart-rebuild.yaml @@ -7,19 +7,24 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ref: 'gh-pages' fetch-depth: 0 - name: Set up Helm - uses: azure/setup-helm@v3 + uses: azure/setup-helm@v4.2.0 with: version: v3.6.3 + - name: Add rstudio helm repo + run: helm repo add rstudio https://helm.rstudio.com + - name: Rebuild index.yaml env: version: v1.2.1 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CR_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | if [[ ! -d "$RUNNER_TOOL_CACHE" ]]; then echo "Cache directory '$RUNNER_TOOL_CACHE' does not exist" >&2 @@ -46,7 +51,7 @@ jobs: - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v6 with: commit-message: Rebuild index.yaml title: Rebuild index.yaml @@ -55,3 +60,24 @@ jobs: run: | echo "Created Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" + + - name: Notify Slack of index.yaml rebuild failure + if: failure() + uses: slackapi/slack-github-action@v1.27.0 + with: + payload-delimiter: "_" + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Rebuild of index.yaml failed, please check the logs. ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK diff --git a/.github/workflows/chart-releaser.yaml b/.github/workflows/chart-releaser.yaml index 2f68df35..87088efd 100644 --- a/.github/workflows/chart-releaser.yaml +++ b/.github/workflows/chart-releaser.yaml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -20,10 +20,13 @@ jobs: git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - name: Install Helm - uses: azure/setup-helm@v3 + uses: azure/setup-helm@v4.2.0 with: version: v3.6.3 + - name: Add rstudio helm repo + run: helm repo add rstudio https://helm.rstudio.com + - name: Run chart-releaser uses: helm/chart-releaser-action@v1.2.0 with: @@ -38,3 +41,24 @@ jobs: charts_repo_url: https://helm.rstudio.com env: CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + + - name: Notify Slack of chart release failure + if: failure() + uses: slackapi/slack-github-action@v1.27.0 + with: + payload-delimiter: "_" + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Chart Release failed, please check the logs. ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK diff --git a/.github/workflows/chart-test.yaml b/.github/workflows/chart-test.yaml index 00543db9..2606978f 100644 --- a/.github/workflows/chart-test.yaml +++ b/.github/workflows/chart-test.yaml @@ -11,90 +11,245 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Helm - uses: azure/setup-helm@v3 + uses: azure/setup-helm@v4.2.0 with: version: v3.6.3 - - uses: actions/setup-python@v2 + - name: Add rstudio helm repo + run: helm repo add rstudio https://helm.rstudio.com + + - uses: actions/setup-python@v5 with: - python-version: 3.7 + python-version: "3.10" - name: Set up chart-testing - uses: helm/chart-testing-action@v2.1.0 + uses: helm/chart-testing-action@v2.6.1 + + - name: Symlink ci-lint -> ci + run: | + for dir in ci/*/lint; do + dir=${dir#ci/} + dir=${dir%/lint} + ln -s ../../ci/${dir}/lint charts/${dir}/ci + done - name: Run chart-testing (list-changed) id: list-changed run: | changed=$(ct list-changed --target-branch main --chart-dirs charts --chart-dirs other-charts) if [[ -n "$changed" ]]; then - echo "::set-output name=changed::true" + echo 'changed=true' >> $GITHUB_OUTPUT fi - name: Run chart-testing (lint changed) + id: ct-lint + if: steps.list-changed.outputs.changed == 'true' run: ct lint --target-branch main --chart-dirs charts --chart-dirs other-charts + continue-on-error: true - name: Run chart-testing (lint all) + id: ct-lint-all run: ct lint --target-branch main --all --chart-dirs charts --chart-dirs other-charts + continue-on-error: true + + - name: Notify Slack of chart linting failure + if: steps.ct-lint.outcome == 'failure' || steps.ct-lint-all.outcome == 'failure' + uses: slackapi/slack-github-action@v1.27.0 + with: + payload-delimiter: "_" + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Linting failed for ${{ steps.ct-lint.outcome == 'failure' && 'changed' || 'all' }} charts. ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + + - name: Fail the workflow if failed linting + if: steps.ct-lint.outcome == 'failure' || steps.ct-lint-all.outcome == 'failure' + run: exit 1 + + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Helm + uses: azure/setup-helm@v4.2.0 + with: + version: v3.6.3 + + - name: Install helm unittest plugin + run: helm plugin install --version v0.6.3 https://github.com/helm-unittest/helm-unittest.git + + - name: Symlink ci-tests -> tests + run: | + for dir in ci/*/tests; do + dir=${dir#ci/} + dir=${dir%/tests} + ln -s ../../ci/${dir}/tests charts/${dir}/tests + done + + - name: Run chart unit tests + id: unittest + run: | + for dir in $(ls -d charts/*/); do + pushd $dir; helm dependencies update; popd + helm unittest $dir + done + continue-on-error: true + + - name: Notify Slack of chart unittest failure + if: steps.unittest.outcome == 'failure' + uses: slackapi/slack-github-action@v1.27.0 + with: + payload-delimiter: "_" + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Chart unit tests failed. ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + + - name: Fail the workflow if failed unittest + if: steps.unittest.outcome == 'failure' + run: exit 1 install: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Helm - uses: azure/setup-helm@v3 + uses: azure/setup-helm@v4.2.0 with: version: v3.6.3 - - uses: actions/setup-python@v2 + - name: Add rstudio helm repo + run: helm repo add rstudio https://helm.rstudio.com + + - uses: actions/setup-python@v5 with: - python-version: 3.7 + python-version: "3.10" - name: Set up chart-testing - uses: helm/chart-testing-action@v2.1.0 + uses: helm/chart-testing-action@v2.6.1 + + - name: Symlink ci-install -> ci + run: | + for dir in ci/*/install; do + dir=${dir#ci/} + dir=${dir%/install} + ln -s ../../ci/${dir}/install charts/${dir}/ci + done - name: Run chart-testing (list-changed) id: list-changed run: | changed=$(ct list-changed --target-branch main --chart-dirs charts --chart-dirs other-charts) if [[ -n "$changed" ]]; then - echo "::set-output name=changed::true" + echo 'changed=true' >> $GITHUB_OUTPUT fi - name: Create kind cluster - uses: helm/kind-action@v1.1.0 - if: ( steps.list-changed.outputs.changed == 'true' ) || ${{ github.ref == 'refs/heads/main' }} + uses: helm/kind-action@v1.10.0 + + - name: Install SealedSecrets Helm Chart + run: | + helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets + helm install sealed-secrets sealed-secrets/sealed-secrets + + - name: Create posit-test namespace + run: kubectl create namespace posit-test + + - name: Create License File Secrets + run: | + echo "${{ secrets.PWB_LICENSE_FILE }}" > pwb.lic + kubectl create secret generic pwb-license --from-file=pwb.lic --namespace posit-test + rm pwb.lic + echo "${{ secrets.PCT_LICENSE_FILE }}" > pct.lic + kubectl create secret generic pct-license --from-file=pct.lic --namespace posit-test + rm pct.lic + echo "${{ secrets.PPM_LICENSE_FILE }}" > ppm.lic + kubectl create secret generic ppm-license --from-file=ppm.lic --namespace posit-test + rm ppm.lic # no allow-failure until https://github.com/actions/toolkit/issues/399 - name: Run chart-testing (install changed) - if: ${{ github.ref != 'refs/heads/main' }} - run: ct install --target-branch main --chart-dirs charts --chart-dirs other-charts + id: ct-install + if: ${{ github.ref != 'refs/heads/main' && steps.list-changed.outputs.changed == 'true' }} + run: ct install --target-branch main --chart-dirs charts --chart-dirs other-charts --excluded-charts rstudio-library --namespace posit-test continue-on-error: true # no allow-failure until https://github.com/actions/toolkit/issues/399 - name: Run chart-testing (install all) - if: ${{ github.ref == 'refs/heads/main' }} - run: ct install --target-branch main --all --chart-dirs charts --chart-dirs other-charts + id: ct-install-all + run: ct install --target-branch main --all --chart-dirs charts --chart-dirs other-charts --excluded-charts rstudio-library --namespace posit-test continue-on-error: true + - name: Notify Slack of chart install failure + if: steps.ct-install.outcome == 'failure' || steps.ct-install-all.outcome == 'failure' + uses: slackapi/slack-github-action@v1.27.0 + with: + payload-delimiter: "_" + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Failure during test installation of ${{ steps.ct-install.outcome == 'failure' && 'changed' || 'all' }} charts. ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + + - name: Fail the workflow if failed installs + if: steps.ct-install.outcome == 'failure' || steps.ct-install-all.outcome == 'failure' + run: exit 1 + check-versions-connect: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Helm - uses: azure/setup-helm@v3 + uses: azure/setup-helm@v4.2.0 with: version: v3.6.3 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..cced9183 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,58 @@ +name: Quarto Publish to docs.posit.co + +on: + workflow_dispatch: + push: + branches: main + +permissions: + id-token: write + contents: read + +jobs: + build-deploy: + runs-on: ubuntu-latest + steps: + - name: Configure AWS credentials + id: creds + uses: aws-actions/configure-aws-credentials@master + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Check out repository + uses: actions/checkout@v4 + + - name: install Just + uses: extractions/setup-just@v2 + + - name: Set up Quarto + uses: quarto-dev/quarto-actions/setup@v2 + with: + version: pre-release + + - name: Render Quarto Project + uses: quarto-dev/quarto-actions/render@v2 + + - run: just push-docs + + - name: Notify Slack of publishing chart documentation failure + if: failure() + uses: slackapi/slack-github-action@v1.27.0 + with: + payload-delimiter: "_" + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Publishing Chart Documentation failed, please check the logs. ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + } + ] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK diff --git a/.gitignore b/.gitignore index fdc6c0f6..ba4ec178 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ helm-docs charts/**/charts/ /*.values /.cr-release-packages + +# helm unittest plugin +__snapshot__ + bin/** !bin/README.md @@ -10,3 +14,4 @@ _site/ _publish.yml /.quarto/ + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e2cdce7..929a8494 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,6 +34,23 @@ We'll try to be as responsive as possible in reviewing and accepting pull reques - If `index.yaml` gets out of date on the repository, see [`./scripts/`](./scripts) for a workflow to fix +## Testing + +Running the [helm chart unit tests](https://github.com/helm-unittest/helm-unittest): + +``` +# install the unittest plugin +helm plugin install https://github.com/helm-unittest/helm-unittest.git + +# unit tests are defined in `charts/$CHART_NAME/tests` + +# test all charts +just test + +# run unit tests for a single chart +just test rstudio-connect +``` + ## Templates The `rstudio-workbench` and `rstudio-connect` charts both make heavy use of the "templating" feature of the Posit Job diff --git a/Justfile b/Justfile index 9afbf6f2..d12a4330 100644 --- a/Justfile +++ b/Justfile @@ -1,13 +1,20 @@ DIFF := "diff" +HELM_DOCS_VERSION := env_var_or_default("HELM_DOCS_VERSION", "1.13.1") +OS := if os() == "macos" {"Darwin"} else if os() == "linux" {"Linux"} else if os() == "windows" {"Windows"} else {""} +ARCH := if arch() == "aarch64" {"arm64"} else if arch() == "x86_64" {"x86_64"} else {""} setup: #!/bin/bash - # TODO: idempotency - - # TODO: check for macos - mkdir -p ./bin/helm-docs-1.5.0/ - curl -L https://github.com/norwoodj/helm-docs/releases/download/v1.5.0/helm-docs_1.5.0_Darwin_x86_64.tar.gz | tar -xzvf - -C ./bin/helm-docs-1.5.0/ - ln -s $PWD/bin/helm-docs-1.5.0/helm-docs $PWD/bin/helm-docs + set -xe + if [ -f ./bin/helm-docs ]; then + echo "Helm-docs is already installed" + exit 0 + fi + echo "Installing helm-docs version {{HELM_DOCS_VERSION}}" + mkdir -p bin + curl -L -s https://github.com/norwoodj/helm-docs/releases/download/v{{HELM_DOCS_VERSION}}/helm-docs_{{HELM_DOCS_VERSION}}_{{OS}}_{{ARCH}}.tar.gz -o bin/helm-docs.tar.gz + tar -C ./bin -xz -f bin/helm-docs.tar.gz helm-docs + rm -rf bin/helm-docs.tar.gz update-lock: #!/bin/bash @@ -68,6 +75,17 @@ snapshot-rsw-diff: fi done +test chart='all': + #!/usr/bin/env bash + set -xe + if [[ "{{ chart }}" == 'all' ]]; then + for dir in $(ls -d {{ justfile_directory() }}/charts/*/); do + helm unittest $dir + done + else + helm unittest "charts/{{ chart }}" + fi + test-connect-interpreter-versions: #!/usr/bin/env bash set -xe @@ -98,3 +116,17 @@ test-connect-interpreter-versions: docker run --rm $image /bin/bash -c "command -v $ex" done done + +push-docs: + #!/usr/bin/env bash + set -euxo pipefail + + s3_args=(--dryrun) + if [[ "${GITHUB_REF:-}" == "refs/heads/main" ]] || [[ "${GITHUB_REF:-}" =~ ^refs/tags/v[0-9]{4}\.[0-9]{2}\.[0-9]+$ ]]; then + s3_args=("") + fi + + # The s3 bucket is s3://docs.rstudio.com/, which is available as https://docs.posit.co/ + aws s3 sync ${s3_args[*]:-} \ + _site \ + "s3://docs.rstudio.com/helm/" diff --git a/_environment b/_environment new file mode 100644 index 00000000..0521a9f7 --- /dev/null +++ b/_environment @@ -0,0 +1 @@ +CURRENT_YEAR=2024 diff --git a/_extensions/posit-dev/posit-docs/_extension.yml b/_extensions/posit-dev/posit-docs/_extension.yml index 4b25a124..a6b83cea 100644 --- a/_extensions/posit-dev/posit-docs/_extension.yml +++ b/_extensions/posit-dev/posit-docs/_extension.yml @@ -1,42 +1,36 @@ title: posit-docs -author: Ashley Henry -version: 0.2.0 -quarto-requred: ">=1.3.340" +author: Ashley Henry, David Aja, Aron Atkins +version: 4.0.2 +quarto-required: ">=1.3.340" contributes: project: project: type: website website: - title: favicon: "assets/images/favicon.svg" bread-crumbs: true navbar: pinned: true logo: "assets/images/posit-icon-fullcolor.svg" - logo-alt: "Posit Documentation" - sidebar: - style: "floating" - collapse-level: 1 - search: true - pinned: false - page-footer: - left: - - text: © 2024 Posit Software, PBC - url: "https://posit.co" - center: | - Posit Product 12345 - + logo-alt: "Posit Documentation" right: - - icon: book - href: https://docs.posit.co - - icon: question-circle-fill - href: https://support.posit.co/hc/en-us - - icon: lightbulb-fill - href: https://solutions.posit.co - formats: - html: - theme: [theme.scss] - link-external-icon: true - link-external-newwindow: true - toc: true - toc-expand: true + - icon: "list" + aria-label: 'Drop-down menu for additional Posit resources' + menu: + - text: "docs.posit.co" + href: "https://docs.posit.co" + - text: "Posit Support" + href: "https://support.posit.co/hc/en-us/" + search: + copy-button: true + show-item-context: true + format: + html: + theme: + light: [theme.scss] + dark: [theme-dark.scss] + link-external-icon: true + link-external-newwindow: true + toc: true + toc-expand: true + include-in-header: "assets/_analytics.html" diff --git a/_extensions/posit-dev/posit-docs/_posit-colors.scss b/_extensions/posit-dev/posit-docs/_posit-colors.scss new file mode 100644 index 00000000..e4bf13a3 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/_posit-colors.scss @@ -0,0 +1,37 @@ +/* Posit Color definitions */ +$posit-blue: #447099; +$posit-light-blue-1: #d1dbe5; +$posit-light-blue-2: #a2b8cb; +$posit-light-blue-3: #7494b1; +$posit-dark-blue-1: #305775; +$posit-dark-blue-2: #213d4f; + +$posit-orange: #ee6331; +$posit-light-orange-1: #edccbf; +$posit-light-orange-2: #eba38c; +$posit-dark-orange-1: #ab4d26; +$posit-dark-orange-2: #80361c; +$posit-dark-orange-3: #451f12; + +$posit-gray: #404041; +$posit-light-gray-1: #c2c2c4; +$posit-light-gray-2: #949494; +$posit-dark-gray-1: #333333; + +$posit-teal: #419599; +$posit-light-teal-1: #c2d9d9; +$posit-light-teal-2: #94bdbf; +$posit-light-teal-3: #70a3a6; +$posit-dark-teal-1: #297075; +$posit-dark-teal-2: #1f4f4f; +$posit-dark-teal-3: #122b2b; + +$posit-green: #72994e; + +$posit-burgundy: #9a4665; +$posit-light-burgundy-1: #d9c4cc; +$posit-light-burgundy-2: #bf96a3; +$posit-light-burgundy-3: #a67380; +$posit-dark-burgundy-1: #78384f; +$posit-dark-burgundy-2: #542938; +$posit-dark-burgundy-3: #2e171f; diff --git a/_extensions/posit-dev/posit-docs/assets/_analytics.html b/_extensions/posit-dev/posit-docs/assets/_analytics.html new file mode 100644 index 00000000..6ba70366 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/_analytics.html @@ -0,0 +1,40 @@ + + diff --git a/_extensions/posit-dev/posit-docs/assets/images/exclamation-circle-dm.svg b/_extensions/posit-dev/posit-docs/assets/images/exclamation-circle-dm.svg new file mode 100644 index 00000000..fbdfd203 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/exclamation-circle-dm.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/assets/images/exclamation-circle.svg b/_extensions/posit-dev/posit-docs/assets/images/exclamation-circle.svg new file mode 100644 index 00000000..6098c8b2 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/exclamation-circle.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/assets/images/exclamation-triangle-dm.svg b/_extensions/posit-dev/posit-docs/assets/images/exclamation-triangle-dm.svg new file mode 100644 index 00000000..63db9932 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/exclamation-triangle-dm.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/assets/images/exclamation-triangle.svg b/_extensions/posit-dev/posit-docs/assets/images/exclamation-triangle.svg new file mode 100644 index 00000000..65d947c9 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/exclamation-triangle.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/assets/images/info-circle-dm.svg b/_extensions/posit-dev/posit-docs/assets/images/info-circle-dm.svg new file mode 100644 index 00000000..6a5c164d --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/info-circle-dm.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/assets/images/info-circle.svg b/_extensions/posit-dev/posit-docs/assets/images/info-circle.svg new file mode 100644 index 00000000..f4f803ad --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/info-circle.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_extensions/posit-dev/posit-docs/assets/images/posit-guide-dm.svg b/_extensions/posit-dev/posit-docs/assets/images/posit-guide-dm.svg new file mode 100644 index 00000000..b0c67d11 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/posit-guide-dm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/assets/images/posit-guide-ltmd.svg b/_extensions/posit-dev/posit-docs/assets/images/posit-guide-ltmd.svg new file mode 100644 index 00000000..f2c33c23 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/posit-guide-ltmd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/assets/images/posit-guide-open-dm.svg b/_extensions/posit-dev/posit-docs/assets/images/posit-guide-open-dm.svg new file mode 100644 index 00000000..d6b0e2b2 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/posit-guide-open-dm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/assets/images/posit-guide-open-ltmd.svg b/_extensions/posit-dev/posit-docs/assets/images/posit-guide-open-ltmd.svg new file mode 100644 index 00000000..77464c09 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/assets/images/posit-guide-open-ltmd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/assets/images/posit-logo-black-TM.svg b/_extensions/posit-dev/posit-docs/assets/images/posit-logo-black-TM.svg index b85676de..9121db29 100644 --- a/_extensions/posit-dev/posit-docs/assets/images/posit-logo-black-TM.svg +++ b/_extensions/posit-dev/posit-docs/assets/images/posit-logo-black-TM.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/_extensions/posit-dev/posit-docs/theme-dark.scss b/_extensions/posit-dev/posit-docs/theme-dark.scss new file mode 100644 index 00000000..0d14d4a9 --- /dev/null +++ b/_extensions/posit-dev/posit-docs/theme-dark.scss @@ -0,0 +1,408 @@ +/*-- scss:defaults --*/ + +// import font +@import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap"); + +// import shared colors +@import '_posit-colors'; + +/*-- scss:variables --*/ +$primary: $posit-teal; +$dark-md-body: $posit-light-gray-1; +$dark-md-background: #0c1721; + +// Feature preview heading colors +$preview-header: $posit-orange; /* posit orange, contrast: 8.45 */ +$preview-header-border: darken($preview-header, 5%); + +// scss-docs-end color-variables + +// Typography +// Font, line-height, and color for body text, headings, and more. + +//scss-font-start font-variables +$font-family-sans-serif: "Open Sans", "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, + sans-serif, system-ui; +$font-family-monospace: "Source Code Pro", monospace; +$font-family-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +$font-size-base: 1rem; +// scss-docs-end font-variables + +//font and body color + +$body-color: $dark-md-body; +$popover-bg: $posit-green !default; + +// scss-docs-start font-sizes - seems that I have to keep these in the style sheet? +$h1-font-size: 44px; +$h2-font-size: 28px; +x h1 { + size: $h1-font-size; +} +h2 { + size: $h2-font-size; +} +// scss-docs-end font-sizes + +// Headings +// scss-docs-start headings-variables +$headings-color: #ffffff; +// scss-docs-end headings-variables + +// Customize the navbar +$navbar-bg: lighten($dark-md-background, 5%); +$navbar-fg: #ffffff; + +// CSS overrides + +// Body +// +// Settings for the `` element. + +/* Body font */ +body { + font-weight: 400 !important; +} + +//$body-color: $posit-green !default; +$body-bg: $dark-md-background !default; // dark mode change + +// Nav and footer + +/* Nav bar */ + +.navbar-title { + color: #ffffff; // dark theme change +} + +.nav-link { + font-family: $font-family-monospace; + text-transform: uppercase; + letter-spacing: 0.03em; + font-size: 14px !important; + font-weight: 500 !important; + color: #fff !important; +} + +.navbar-nav .nav-link.active, +.navbar-nav .nav-link.show { + color: $posit-teal !important; + font-weight: 700 !important; +} + +/* Nav bar right hamburger menu */ + +.dropdown-item:hover, +.dropdown-item:focus { + color: var(--bs-dropdown-link-hover-color); + background-color: #0f1c29 !important; +} + +/* Search results */ + +.aa-DetachedOverlay .aa-SourceHeader .search-result-header, #quarto-search-results .aa-SourceHeader .search-result-header { + font-weight: 600 !important; +} + +.aa-DetachedOverlay a.search-result-link, #quarto-search-results a.search-result-link { + color: $posit-blue !important; + text-decoration: none; +} + +.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container, #quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container { + background-color: #c2c2c4 !important; + font-weight: 500 !important; +} + +.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item, #quarto-search-results li.aa-Item[aria-selected=false] .search-item { + background-color: #ffffff !important; + +} + +.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-section, .aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text, .aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-title-container, .aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text-container, #quarto-search-results li.aa-Item[aria-selected=true] .search-item.search-result-more, #quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-section, #quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text, #quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-title-container, #quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text-container { + color: #ffffff !important; + background-color: $posit-blue !important; + font-weight: 400 !important; +} + +.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text, .aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-title-container, .aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text-container, #quarto-search-results li.aa-Item[aria-selected=false] .search-item.search-result-more, #quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-section, #quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text, #quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-title-container, #quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text-container { + color: #000000 !important; +} + +.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item { + background-color: $posit-blue !important; +} + +.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item mark.search-match, .aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-match.mark, #quarto-search-results li.aa-Item[aria-selected=false] .search-item mark.search-match, #quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-match.mark { + color: $posit-dark-teal-1 !important; + background-color: #ffffff !important; + font-weight:700 !important; +} + +.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item.search-result-more, .aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-section, .aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text, .aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-title-container, .aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text-container, #quarto-search-results li.aa-Item[aria-selected=false] .search-item.search-result-more, #quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-section, #quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text, #quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-title-container, #quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text-container { + color: $posit-dark-gray-1 !important; +} + +.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item mark.search-match, .aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-match.mark, #quarto-search-results li.aa-Item[aria-selected=true] .search-item mark.search-match, #quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-match.mark { + color: #000000 !important; + background-color: $posit-light-gray-1 !important; +} + +/* Footer */ + +.nav-footer { + color: #ffffff !important; + border-top: solid $posit-gray 1px; +} + +/* Footer icons */ +.nav-footer a { + color: #ffffff !important; +} + +// Footnotes + +.footnote-back { + color: $posit-light-teal-2; +} + +// Breadcrumbs + +.quarto-title-breadcrumbs .breadcrumb li:last-of-type a { + color: $posit-light-gray-1 !important; +} + +// Page navigation + +.nav-page .nav-page-text { + color: $posit-light-gray-1; +} + +/* Inline code */ +p code:not(.sourceCode), +li code:not(.sourceCode), +td code:not(.sourceCode) { + background-color: #6e768166 !important; + color: #ffffff; +} + +// Code blocks + +pre code:not(.sourceCode) { + background-color: #1a3146 !important; + color: #ffffff; + padding: 9px !important; +} + +/* Code block title*/ + +.quarto-dark .code-with-filename .code-with-filename-file { + background-color: #000000 !important; + border: none; +} + +.code-with-filename strong { + color: #6e9ac3; +} + +/* Code block background */ +$code-block-bg: lighten($dark-md-background, 10%); + +/* Copy button */ + +$btn-code-copy-color: #ffffff; +$btn-code-copy-color-active: $posit-orange; +$callout-icon-scale: 70%; +$tooltip-color: #ffffff !default; // Copied! color + +// Tabs and pills + +/* Tabs */ + +.nav-tabs .nav-link.active { + color: $posit-teal !important; +} + +.nav-tabs .nav-link { + text-transform: none !important; + font-family: $font-family-sans-serif; + color: #ffffff !important; +} + +.nav-tabs .nav-link:hover, +.nav-link:focus { + color: $posit-teal !important; +} + +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + text-decoration: none !important; +} +/* Pills */ + +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + background-color: $posit-dark-teal-1 !important; +} + +.nav-pills .nav-link:hover, +.nav-link:focus { + isolation: isolate; + // color: $posit-teal !important; + border: none !important; +} + +.nav-pills .nav-link.active, +.nav-link:hover { + color: #ffffff !important; +} + +// Sidebar and toc + +/* Left nav - letter spacing */ +.sidebar-navigation li a { + color: #ffffff; +} + +.sidebar-navigation li a:hover { + color: inherit; +} + +.sidebar-item-container .active, +div.sidebar-item-container .show > .nav-link, +div.sidebar-item-container .sidebar-link > code { + color: $posit-teal !important; +} + +// Lists + +/* List disc colors */ +li::marker { + color: $posit-teal; +} + +// Callouts + +.callout.callout-style-default:not(.no-icon) div.callout-title-container { + color: #ffffff !important; +} + +div.callout.callout-style-default > div.callout-header { + opacity: none; +} + +/* Note */ + +div.callout-note.callout { + border-left-color: $posit-dark-blue-2 !important; + border-right: 1px solid $posit-dark-blue-2 !important; + border-top: 1px solid $posit-dark-blue-2 !important; + border-bottom: 1px solid $posit-dark-blue-2 !important; +} + +div.callout-note .callout-icon::before { + // base64 -i _extensions/posit-docs/assets/images/info-circle-dm.svg + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iIzAwMDAwMCIgY2xhc3M9ImJpIGJpLWluZm8tY2lyY2xlIiB2aWV3Qm94PSIwIDAgMTYgMTYiPgogIDxwYXRoIGQ9Ik04IDE1QTcgNyAwIDEgMSA4IDFhNyA3IDAgMCAxIDAgMTRtMCAxQTggOCAwIDEgMCA4IDBhOCA4IDAgMCAwIDAgMTYiLz4KICA8cGF0aCBkPSJtOC45MyA2LjU4OC0yLjI5LjI4Ny0uMDgyLjM4LjQ1LjA4M2MuMjk0LjA3LjM1Mi4xNzYuMjg4LjQ2OWwtLjczOCAzLjQ2OGMtLjE5NC44OTcuMTA1IDEuMzE5LjgwOCAxLjMxOS41NDUgMCAxLjE3OC0uMjUyIDEuNDY1LS41OThsLjA4OC0uNDE2Yy0uMi4xNzYtLjQ5Mi4yNDYtLjY4Ni4yNDYtLjI3NSAwLS4zNzUtLjE5My0uMzA0LS41MzN6TTkgNC41YTEgMSAwIDEgMS0yIDAgMSAxIDAgMCAxIDIgMCIvPgo8L3N2Zz4=") !important; +} + +div.callout-note.callout-style-default > .callout-header { + background-color: $posit-blue !important; +} + +/* Warning */ + +div.callout-warning.callout { + border-left-color: $posit-dark-orange-2 !important; + border-right: 1px solid $posit-dark-orange-2 !important; + border-top: 1px solid $posit-dark-orange-2 !important; + border-bottom: 1px solid $posit-dark-orange-2 !important; +} + +div.callout-warning .callout-icon::before { + // base64 -i _extensions/posit-docs/assets/images/exclamation-triangle-dm.svg + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iIzAwMDAwMCIgY2xhc3M9ImJpIGJpLWV4Y2xhbWF0aW9uLXRyaWFuZ2xlIiB2aWV3Qm94PSIwIDAgMTYgMTYiPgogIDxwYXRoIGQ9Ik03LjkzOCAyLjAxNkEuMTMuMTMgMCAwIDEgOC4wMDIgMmEuMTMuMTMgMCAwIDEgLjA2My4wMTYuMTUuMTUgMCAwIDEgLjA1NC4wNTdsNi44NTcgMTEuNjY3Yy4wMzYuMDYuMDM1LjEyNC4wMDIuMTgzYS4yLjIgMCAwIDEtLjA1NC4wNi4xLjEgMCAwIDEtLjA2Ni4wMTdIMS4xNDZhLjEuMSAwIDAgMS0uMDY2LS4wMTcuMi4yIDAgMCAxLS4wNTQtLjA2LjE4LjE4IDAgMCAxIC4wMDItLjE4M0w3Ljg4NCAyLjA3M2EuMTUuMTUgMCAwIDEgLjA1NC0uMDU3bTEuMDQ0LS40NWExLjEzIDEuMTMgMCAwIDAtMS45NiAwTC4xNjUgMTMuMjMzYy0uNDU3Ljc3OC4wOTEgMS43NjcuOTggMS43NjdoMTMuNzEzYy44ODkgMCAxLjQzOC0uOTkuOTgtMS43Njd6Ii8+CiAgPHBhdGggZD0iTTcuMDAyIDEyYTEgMSAwIDEgMSAyIDAgMSAxIDAgMCAxLTIgME03LjEgNS45OTVhLjkwNS45MDUgMCAxIDEgMS44IDBsLS4zNSAzLjUwN2EuNTUyLjU1MiAwIDAgMS0xLjEgMHoiLz4KPC9zdmc+") !important; +} + +div.callout-warning.callout-style-default > .callout-header { + background-color: $posit-dark-orange-1 !important; +} + +/* Important */ + +div.callout-important.callout { + border-left-color: $posit-dark-burgundy-2 !important; + border-right: 1px solid $posit-dark-burgundy-2 !important; + border-top: 1px solid $posit-dark-burgundy-2 !important; + border-bottom: 1px solid $posit-dark-burgundy-2 !important; +} + +div.callout-important .callout-icon::before { + // base64 -i _extensions/posit-docs/assets/images/exclamation-circle-dm.svg + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iIzAwMDAwMCIgY2xhc3M9ImJpIGJpLWV4Y2xhbWF0aW9uLWNpcmNsZSIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCAxNUE3IDcgMCAxIDEgOCAxYTcgNyAwIDAgMSAwIDE0bTAgMUE4IDggMCAxIDAgOCAwYTggOCAwIDAgMCAwIDE2Ii8+CiAgPHBhdGggZD0iTTcuMDAyIDExYTEgMSAwIDEgMSAyIDAgMSAxIDAgMCAxLTIgME03LjEgNC45OTVhLjkwNS45MDUgMCAxIDEgMS44IDBsLS4zNSAzLjUwN2EuNTUyLjU1MiAwIDAgMS0xLjEgMHoiLz4KPC9zdmc+") !important; +} + +div.callout-important.callout-style-default > .callout-header { + background-color: $posit-burgundy !important; +} + +// Tables + +.table > :not(caption) > * > * { + border-top: 2px solid #101e2b; +} + +/* Striped table styles */ + +.table-striped > tbody > tr:nth-of-type(odd) > * { + //--bs-table-bg-type: #001C2B !important; + --bs-table-bg-type: #101e2b !important; +} + +/* Striped table hover */ + +.table-hover > tbody > tr:hover > * { + //--bs-table-color-state: var(--bs-table-hover-color); + --bs-table-bg-state: #001c2b !important; +} + +// Table caption + +.panel-caption, +.figure-caption, +.subfigure-caption, +.table-caption, +figcaption, +caption { + font-size: 1rem; + color: $body-color !important; +} + +// Specialty headers + +/* the feature PREVIEW header */ +.preview-header > h1:after, +.preview-header > h2:after, +.preview-header > h3:after, +.preview-header > h4:after, +header h1 .preview-header, +div span.preview-feature { + background-color: $preview-header; + color: #ffffff; + border: 1px solid $preview-header-border; + font-weight: 600; + font-size: 9pt !important; + padding: 0rem 0.4rem; +} + +div span.preview-feature { + margin-left: 1em; + text-transform: uppercase; +} + +// Specialty lists +// Groovy list - dark mode change + +ol.groovyAlpha li > p:before { + content: counter(list-counter, lower-alpha); + font-weight: 600; +} diff --git a/_extensions/posit-dev/posit-docs/theme.scss b/_extensions/posit-dev/posit-docs/theme.scss index bad2b7b1..2a4554b5 100644 --- a/_extensions/posit-dev/posit-docs/theme.scss +++ b/_extensions/posit-dev/posit-docs/theme.scss @@ -1,40 +1,37 @@ /*-- scss:defaults --*/ // import font -@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap'); +@import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap"); + +// import shared colors +@import '_posit-colors'; /*-- scss:variables --*/ +$primary: $posit-blue; -// scss-docs-start color-variables -$posit-blue: #447099; -$posit-dark-blue-1: #305775; -$posit-dark-blue-2: #213D4F; -$posit-orange: #EE6331; -$posit-gray: #404041; -$posit-teal: #419599; -$posit-green: #72994E; -$posit-burgundy:#9A4665; -$posit-burgundy-1:#78384F; -$posit-burgundy-2:#542938; +// Feature preview heading colors +$preview-header: #ee6331; /* posit orange, contrast: 8.45 */ +$preview-header-border: darken($preview-header, 5%); -$primary: $posit-blue; // scss-docs-end color-variables // Typography // Font, line-height, and color for body text, headings, and more. //scss-font-start font-variables -$font-family-sans-serif: "Open Sans", "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, system-ui; +$font-family-sans-serif: "Open Sans", "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, + sans-serif, system-ui; $font-family-monospace: "Source Code Pro", monospace; $font-family-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; $font-size-base: 1rem; // scss-docs-end font-variables +//font and body color $body-color: $posit-gray; // scss-docs-start font-sizes -$h1-font-size:44px; -$h2-font-size:28px; +$h1-font-size: 44px; +$h2-font-size: 28px; h1 { size: $h1-font-size; @@ -44,7 +41,6 @@ h2 { } // scss-docs-end font-sizes - // Headings // scss-docs-start headings-variables $headings-font-weight: 300 !important; @@ -64,68 +60,338 @@ $list-group-color: $primary !default; // CSS overrides +// Body +// +// Settings for the `` element. + +/* Body font */ +body { + letter-spacing: -0.2px !important; + font-weight: 300 !important; +} + +// Nav and footer + +/* Navbar */ + .navbar { - box-shadow: 0 0 0.2rem #0000001a, 0 0.1rem 0.4rem #0003; - transition: transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s; + box-shadow: + 0 0 0.2rem #0000001a, + 0 0.1rem 0.4rem #0003; + transition: + transform 0.25s cubic-bezier(0.1, 0.7, 0.1, 1), + box-shadow 0.25s; } .navbar-title { - font-family: $font-family-sans-serif; - font-size: $font-size-base; - font-weight: 500; + font-family: $font-family-sans-serif; + font-size: $font-size-base; + font-weight: 500; +} + +/* Style for the version included in the website title */ +.navbar-title small { + font-size: 14px; + display: block; + padding-left: 1em; } .nav-link { - font-family: $font-family-monospace; - text-transform: uppercase; - letter-spacing: .03em; - font-size: 14px !important; - font-weight: 500 !important; + font-family: $font-family-monospace; + text-transform: uppercase; + letter-spacing: 0.03em; + font-size: 14px !important; + font-weight: 500 !important; + color: $posit-gray !important; +} + +.navbar-nav .nav-link.active, +.navbar-nav .nav-link.show { + color: #000000 !important; + font-weight: 700 !important; } +/* Footer */ + .nav-footer { - font-family: $font-family-monospace; - text-transform: uppercase; - font-size: 14px; - border-top: solid #0000001a .01em; - align-items: center !important; + font-family: $font-family-monospace; + text-transform: uppercase; + font-size: 14px; + border-top: solid #0000001a 0.01em; + align-items: center !important; +} + +.nav-footer .nav-footer-center { + min-height: min-content; +} + +/* Footer icons */ + +/* Full Posit logo - currently, unused */ +#footer-right-full-posit-logo { + width: 70px; + min-width: 70px; +} + +/* Posit guide book */ +#footer-right-logo { + width: 24px; + min-width: 24px; + margin-left: -3px !important; + margin-right: -3px !important; + padding-top: 1px; +} + +/* Posit icon fullcolor */ +#footer-right-posit-logo { + width: 18px; + min-width: 18px; + margin-left: -3px !important; + margin-right: -3px !important; + padding-top: 1px; +} + +/* Posit logo - footer +#footer-logo { + width: 70px; + min-width: 70px; } +*/ -/* Tabs */ +.bi-question-circle-fill { + font-size: 18px !important; +} + +.bi-lightbulb-fill { + font-size: 18px !important; +} + +// Footnotes + +.footnote-back { + font-size: 16px !important; + font-weight: 900px !important; + color: $posit-dark-blue-1; +} + +// Tabs and pills + +/* Tabs */ .nav-tabs .nav-link { - text-transform: none !important; - font-family: $font-family-sans-serif; + text-transform: none !important; + font-family: $font-family-sans-serif; + color: $posit-gray !important; } -/* Mini TOC */ -.sidebar nav[role=doc-toc]>ul li a { - text-transform: none !important; - font-family: $font-family-sans-serif; - font-size: 16px; - font-weight: 300 !important; - letter-spacing: .05em !important; +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: #000000 !important; + font-weight: 700 !important; + text-decoration: underline 1px $posit-orange !important; +} + +.nav-tabs .nav-link:hover, +.nav-link:focus { + color: $posit-blue !important; +} + +/* Pills */ + +.nav-pills { + border: none !important; +} + +.nav-pills, +.panel-underline { + > .nav { + display: flex; + border: none !important; + flex-direction: row; + justify-content: center; + .nav-link { + cursor: pointer; + } + } +} + +.nav-pills > .nav .nav-link { + border: none !important; +} + +.nav-pills, +.panel-underline { + .tab-content { + padding-left: 0; + padding-right: 0; + border: none; + } +} + +.nav-pills .nav-link.active, +.nav-pills .nav-item.show .nav-link { + color: #ffffff !important; + text-decoration: none !important; +} + +.nav-pills .nav-link:hover, +.nav-link:focus { + isolation: isolate; + color: $posit-blue !important; + border: none !important; +} + +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + color: #ffffff !important; +} + +// Sidebar and toc + +/* Left nav */ +.sidebar-item-container .active { + font-weight: 500; } /* Left nav - letter spacing */ .sidebar-navigation li a { - letter-spacing: .03em; - font-size: 16px; + letter-spacing: 0.03em; + font-size: 16px; } +/* Left nav - letter spacing */ +.sidebar-navigation li a { + letter-spacing: -0.2px; + line-height: normal; +} -/* Posit logo - footer */ -#footer-logo { - width: 70px; - min-width: 70px; +/* Mini TOC */ +.sidebar nav[role="doc-toc"] > ul li a { + text-transform: none !important; + font-family: $font-family-sans-serif; + font-weight: 400 !important; + letter-spacing: -0.2px !important; } -/* Footer */ -.nav-footer .nav-footer-center { - min-height: min-content; +.sidebar nav[role="doc-toc"] ul > li > a.active, +.sidebar nav[role="doc-toc"] ul > li > ul > li > a.active { + font-weight: 700 !important; } +// Lists + /* List disc colors */ li::marker { - color: $primary; + color: $primary; +} + +// Callouts + +.callout.callout-style-default:not(.no-icon) div.callout-title-container { + color: $posit-dark-gray-1 !important; +} + +/* Note */ + +div.callout-note.callout { + border-left-color: $posit-blue !important; +} + +div.callout-note .callout-icon::before { + // base64 -i _extensions/posit-docs/assets/images/info-circle.svg + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iIzE3MjEyQiIgY2xhc3M9ImJpIGJpLWluZm8tY2lyY2xlIiB2aWV3Qm94PSIwIDAgMTYgMTYiPgogIDxwYXRoIGQ9Ik04IDE1QTcgNyAwIDEgMSA4IDFhNyA3IDAgMCAxIDAgMTRtMCAxQTggOCAwIDEgMCA4IDBhOCA4IDAgMCAwIDAgMTYiLz4KICA8cGF0aCBkPSJtOC45MyA2LjU4OC0yLjI5LjI4Ny0uMDgyLjM4LjQ1LjA4M2MuMjk0LjA3LjM1Mi4xNzYuMjg4LjQ2OWwtLjczOCAzLjQ2OGMtLjE5NC44OTcuMTA1IDEuMzE5LjgwOCAxLjMxOS41NDUgMCAxLjE3OC0uMjUyIDEuNDY1LS41OThsLjA4OC0uNDE2Yy0uMi4xNzYtLjQ5Mi4yNDYtLjY4Ni4yNDYtLjI3NSAwLS4zNzUtLjE5My0uMzA0LS41MzN6TTkgNC41YTEgMSAwIDEgMS0yIDAgMSAxIDAgMCAxIDIgMCIvPgo8L3N2Zz4=") !important; +} + +div.callout-note.callout-style-default > .callout-header { + background-color: #dce7f2 !important; +} + +/* Warning */ +div.callout-warning.callout { + border-left-color: $posit-orange !important; +} + +div.callout-warning .callout-icon::before { + // base64 -i _extensions/posit-docs/assets/images/exclamation-triangle.svg + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iIzQ1MUYxMiIgY2xhc3M9ImJpIGJpLWV4Y2xhbWF0aW9uLXRyaWFuZ2xlIiB2aWV3Qm94PSIwIDAgMTYgMTYiPgogIDxwYXRoIGQ9Ik03LjkzOCAyLjAxNkEuMTMuMTMgMCAwIDEgOC4wMDIgMmEuMTMuMTMgMCAwIDEgLjA2My4wMTYuMTUuMTUgMCAwIDEgLjA1NC4wNTdsNi44NTcgMTEuNjY3Yy4wMzYuMDYuMDM1LjEyNC4wMDIuMTgzYS4yLjIgMCAwIDEtLjA1NC4wNi4xLjEgMCAwIDEtLjA2Ni4wMTdIMS4xNDZhLjEuMSAwIDAgMS0uMDY2LS4wMTcuMi4yIDAgMCAxLS4wNTQtLjA2LjE4LjE4IDAgMCAxIC4wMDItLjE4M0w3Ljg4NCAyLjA3M2EuMTUuMTUgMCAwIDEgLjA1NC0uMDU3bTEuMDQ0LS40NWExLjEzIDEuMTMgMCAwIDAtMS45NiAwTC4xNjUgMTMuMjMzYy0uNDU3Ljc3OC4wOTEgMS43NjcuOTggMS43NjdoMTMuNzEzYy44ODkgMCAxLjQzOC0uOTkuOTgtMS43Njd6Ii8+CiAgPHBhdGggZD0iTTcuMDAyIDEyYTEgMSAwIDEgMSAyIDAgMSAxIDAgMCAxLTIgME03LjEgNS45OTVhLjkwNS45MDUgMCAxIDEgMS44IDBsLS4zNSAzLjUwN2EuNTUyLjU1MiAwIDAgMS0xLjEgMHoiLz4KPC9zdmc+") !important; +} + +div.callout-warning.callout-style-default > .callout-header { + background-color: #fad8ca !important; +} + +/* Important */ + +div.callout-important.callout { + border-left-color: $posit-burgundy !important; +} + +div.callout-important .callout-icon::before { + // base64 -i _extensions/posit-docs/assets/images/exclamation-circle.svg + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iIzJFMTcxRiIgY2xhc3M9ImJpIGJpLWV4Y2xhbWF0aW9uLWNpcmNsZSIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCAxNUE3IDcgMCAxIDEgOCAxYTcgNyAwIDAgMSAwIDE0bTAgMUE4IDggMCAxIDAgOCAwYTggOCAwIDAgMCAwIDE2Ii8+CiAgPHBhdGggZD0iTTcuMDAyIDExYTEgMSAwIDEgMSAyIDAgMSAxIDAgMCAxLTIgME03LjEgNC45OTVhLjkwNS45MDUgMCAxIDEgMS44IDBsLS4zNSAzLjUwN2EuNTUyLjU1MiAwIDAgMS0xLjEgMHoiLz4KPC9zdmc+") !important; +} + +div.callout-important.callout-style-default > .callout-header { + background-color: #f2dae3 !important; +} + +// Specialty headers + +/* the feature PREVIEW header */ +.preview-header > h1:after, +.preview-header > h2:after, +.preview-header > h3:after, +.preview-header > h4:after, +header h1 .preview-header { + content: "Preview feature"; + margin-left: 1em; + position: relative; + border-radius: 50rem !important; + top: -0.5em; +} + +.preview-header > h1:after, +.preview-header > h2:after, +.preview-header > h3:after, +.preview-header > h4:after, +header h1 .preview-header, +div span.preview-feature { + color: $preview-header; + border: 1px solid $preview-header-border; + font-weight: 400; + font-size: 9pt !important; + padding: 0rem 0.4rem; +} + +div span.preview-feature { + margin-left: 1em; + text-transform: uppercase; +} + +// Specialty lists + +/* Callout steps for images with multiple items/steps shown in single image */ + +ol.groovyAlpha { + list-style: none; + counter-reset: list-counter; +} + +ol.groovyAlpha li { + counter-increment: list-counter; +} + +ol.groovyAlpha li > p:before { + content: counter(list-counter, lower-alpha); + width: 20px; + height: 20px; + text-align: center; + margin-right: 10px; + color: #fff; + background-color: #fc403b; + display: inline-block; + border-radius: 10px; + font-size: 14px; + line-height: 16px; + vertical-align: middle; } diff --git a/_quarto.yml b/_quarto.yml index 3f2c9fa6..d8d897e7 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -1,5 +1,8 @@ project: type: posit-docs + pre-render: + - just setup + - just docs render: - charts/rstudio-workbench/README.md - charts/rstudio-workbench/NEWS.md @@ -19,17 +22,28 @@ project: filters: - include-code-files -format: - posit-docs-html: - toc: true - website: title: Posit Helm Charts + site-url: https://docs.posit.co/helm bread-crumbs: true repo-url: https://github.com/rstudio/helm repo-actions: [edit, issue] - page-footer: - center: Posit Helm Charts + page-footer: + left: | + Copyright © {{< env CURRENT_YEAR >}} Posit Software, PBC. All Rights Reserved. + center: | + Posit Helm Charts + right: + - icon: question-circle-fill + aria-label: 'Link to Posit Support' + href: "https://support.posit.co/hc/en-us" + - icon: lightbulb-fill + aria-label: 'Link to Posit Solutions' + href: "https://solutions.posit.co/" + - text: "" + href: "https://docs.posit.co/" + - text: "" + href: "https://posit.co/" sidebar: style: "floating" collapse-level: 1 diff --git a/charts/_templates.gotmpl b/charts/_templates.gotmpl index bce09a9a..476b8082 100644 --- a/charts/_templates.gotmpl +++ b/charts/_templates.gotmpl @@ -40,49 +40,55 @@ Workbench. {{- define "rstudio.disclaimer" }} -## For Production +## For production -To ensure a stable production deployment, please: +To ensure a stable production deployment: -* Ensure you "pin" the version of the Helm chart that you are using. You can do - this using the `helm dependency` command and the associated "Chart.lock" files - or the `--version` flag. **IMPORTANT: This protects you from breaking changes** -* Before upgrading, to avoid breaking changes, use `helm diff upgrade` to check - for breaking changes -* Pay close attention to [`NEWS.md`](./NEWS.md) for updates on breaking - changes, as well as documentation below on how to use the chart +* "Pin" the version of the Helm chart that you are using. You can do this using the: + * `helm dependency` command *and* the associated "Chart.lock" files *or* + * the `--version` flag. + + ::: {.callout-important} + This protects you from breaking changes. + ::: +* Before upgrading check for breaking changes using `helm-diff` plugin and `helm diff upgrade`. +* Read [`NEWS.md`](./NEWS.md) for updates on breaking changes and the documentation below on how to use the chart. {{- end }} {{- define "rstudio.best-practices" }} -## Best Practices +## Best practices Helm charts are very useful tools for deploying resources into Kubernetes, however, they do require some familiarity with kubernetes and `helm` itself. Please ensure you have adequate training and IT support before deploying these charts into production environments. Reach out to your account representative -if you need help deciding whether helm is a good choice for your deployment. +if you need help deciding whether Helm is a good choice for your deployment. To ensure reproducibility in your environment and insulate yourself from future changes, please: -* Ensure you "pin" the version of the Helm chart that you are using. You can do - this using the `helm dependency` command and the associated "Chart.lock" files - or the `--version` flag. **IMPORTANT: This protects you from breaking changes** -* Before upgrading, to avoid breaking changes, use the `helm-diff` plugin and `helm diff upgrade` to check - for breaking changes -* Read [`NEWS.md`](./NEWS.md) for updates on breaking - changes, as well as documentation below on how to use the chart +* "Pin" the version of the Helm chart that you are using. You can do + this using the: + * `helm dependency` command and the associated "Chart.lock" files _or_ + * the `--version` flag. + + :::{.callout-important} + This protects you from breaking changes** + ::: + +* Before upgrading check for breaking changes using `helm-diff` plugin and `helm diff upgrade`. +* Read [`NEWS.md`](./NEWS.md) for updates on breaking changes and the documentation below on how to use the chart. {{- end }} {{- define "rstudio.install" }} {{- $isDev := (regexMatch "[0-9]+\\.[0-9]+\\.[0-9]+-[a-zA-Z\\.0-9]+" .Version) }} -## Installing the Chart +## Installing the chart To install the chart with the release name `my-release` at version {{ template "chart.version" . }}: -```bash +```{.bash} helm repo add rstudio https://helm.rstudio.com {{- if not $isDev }} helm upgrade --install my-release rstudio/{{ template "chart.name" . }} --version={{ template "chart.version" . }} @@ -95,8 +101,9 @@ helm upgrade --install --devel my-release rstudio/{{ template "chart.name" . }} {{- end }} ``` -To explore other chart versions, take a look at: -``` +To explore other chart versions, look at: + +```{.bash} helm search repo {{ if $isDev }}--devel {{ end }}rstudio/{{ template "chart.name" . }} -l ``` @@ -106,15 +113,15 @@ helm search repo {{ if $isDev }}--devel {{ end }}rstudio/{{ template "chart.name ## Licensing -This chart supports activating the product using a license file, license key, or license server. In the case of a license file or key, we recommend against placing it in your values file directly. - -### License File +This chart supports activating the product using a *license file*. We recommend storing a license file as a `Secret` and setting the `license.file.secret` and `license.file.secretKey` values accordingly. First, create the secret declaratively with YAML or imperatively using the following command: -`kubectl create secret generic {{ .Name }}-license --from-file=licenses/{{ .Name }}.lic` +```{.bash} +kubectl create secret generic {{ .Name }}-license --from-file=licenses/{{ .Name }}.lic +``` Second, specify the following values: @@ -127,15 +134,9 @@ license: Alternatively, license files can be set during `helm install` with the following argument: -`--set-file license.file.contents=licenses/{{ .Name }}.lic` - -### License Key - -Set a license key directly in your values file (`license.key`) or during `helm install` with the argument `--set license.key=XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX`. - -### License Server - -Set a license server directly in your values file (`license.server`) or during `helm install` with the argument `--set license.server=`. +```{.bash} +--set-file license.file.contents=licenses/{{ .Name }}.lic +``` {{- end }} diff --git a/charts/posit-chronicle/.helmignore b/charts/posit-chronicle/.helmignore index 0e8a0eb3..f70705f1 100644 --- a/charts/posit-chronicle/.helmignore +++ b/charts/posit-chronicle/.helmignore @@ -21,3 +21,6 @@ .idea/ *.tmproj .vscode/ + +# chart tests +tests/ diff --git a/charts/posit-chronicle/Chart.yaml b/charts/posit-chronicle/Chart.yaml index d3075872..20cb6c33 100644 --- a/charts/posit-chronicle/Chart.yaml +++ b/charts/posit-chronicle/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 name: posit-chronicle description: Official Helm chart for Posit Chronicle Server -version: 0.3.0 -appVersion: 2024.03.0 +version: 0.3.6 +appVersion: 2024.11.0 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png home: https://www.posit.co sources: diff --git a/charts/posit-chronicle/NEWS.md b/charts/posit-chronicle/NEWS.md index b810a951..55fd64e2 100644 --- a/charts/posit-chronicle/NEWS.md +++ b/charts/posit-chronicle/NEWS.md @@ -1,5 +1,29 @@ # Changelog +## 0.3.6 + +- Bump Chronicle to version 2024.11.0 + +## 0.3.5 + +- Change the default value for LocalStorage.Enabled to `true` in order for installations with the default values to work out of the box. + +## 0.3.4 + +- Add helm unit test scaffold. + +## 0.3.3 + +- Move the values files for linting and installation testing outside the chart directory so that we can iterate on them without releasing a new version of the chart + +## 0.3.2 + +- Bump Chronicle to version 2024.09.0 + +## 0.3.1 + +- Documentation site updates + ## 0.3.0 - Bump Chronicle to version 2024.03.0 diff --git a/charts/posit-chronicle/README.md b/charts/posit-chronicle/README.md index fd9522a1..77e86ac9 100644 --- a/charts/posit-chronicle/README.md +++ b/charts/posit-chronicle/README.md @@ -1,6 +1,6 @@ # Posit Chronicle -![Version: 0.3.0](https://img.shields.io/badge/Version-0.3.0-informational?style=flat-square) ![AppVersion: 2024.03.0](https://img.shields.io/badge/AppVersion-2024.03.0-informational?style=flat-square) +![Version: 0.3.6](https://img.shields.io/badge/Version-0.3.6-informational?style=flat-square) ![AppVersion: 2024.11.0](https://img.shields.io/badge/AppVersion-2024.11.0-informational?style=flat-square) #### _Official Helm chart for Posit Chronicle Server_ @@ -8,29 +8,33 @@ Chronicle helps data science managers and other stakeholders understand their organization's use of other Posit products, primarily Posit Connect and Workbench. -## For Production +## For production -To ensure a stable production deployment, please: +To ensure a stable production deployment: -* Ensure you "pin" the version of the Helm chart that you are using. You can do - this using the `helm dependency` command and the associated "Chart.lock" files - or the `--version` flag. **IMPORTANT: This protects you from breaking changes** -* Before upgrading, to avoid breaking changes, use `helm diff upgrade` to check - for breaking changes -* Pay close attention to [`NEWS.md`](./NEWS.md) for updates on breaking - changes, as well as documentation below on how to use the chart +* "Pin" the version of the Helm chart that you are using. You can do this using the: + * `helm dependency` command *and* the associated "Chart.lock" files *or* + * the `--version` flag. + + ::: {.callout-important} + This protects you from breaking changes. + ::: -## Installing the Chart +* Before upgrading check for breaking changes using `helm-diff` plugin and `helm diff upgrade`. +* Read [`NEWS.md`](./NEWS.md) for updates on breaking changes and the documentation below on how to use the chart. -To install the chart with the release name `my-release` at version 0.3.0: +## Installing the chart -```bash +To install the chart with the release name `my-release` at version 0.3.6: + +```{.bash} helm repo add rstudio https://helm.rstudio.com -helm upgrade --install my-release rstudio/posit-chronicle --version=0.3.0 +helm upgrade --install my-release rstudio/posit-chronicle --version=0.3.6 ``` -To explore other chart versions, take a look at: -``` +To explore other chart versions, look at: + +```{.bash} helm search repo rstudio/posit-chronicle -l ``` @@ -56,7 +60,7 @@ pod: mountPath: "/var/lib/rstudio-server/audit" sidecar: - name: chronicle-agent - image: ghcr.io/rstudio/chronicle-agent:2024.03.0 + image: ghcr.io/rstudio/chronicle-agent:2024.11.0 volumeMounts: - name: logs mountPath: "/var/lib/rstudio-server/audit" @@ -72,7 +76,7 @@ API key from a Kubernetes Secret is used to unlock more detailed metrics: pod: sidecar: - name: chronicle-agent - image: ghcr.io/rstudio/chronicle-agent:2024.03.0 + image: ghcr.io/rstudio/chronicle-agent:2024.11.0 env: - name: CHRONICLE_SERVER_ADDRESS value: "http://chronicle-server.default" @@ -160,7 +164,7 @@ The credentials Chronicle uses for S3 storage must have the following permission | config.HTTPS.Certificate | string | `""` | | | config.HTTPS.Enabled | bool | `false` | | | config.HTTPS.Key | string | `""` | | -| config.LocalStorage.Enabled | bool | `false` | | +| config.LocalStorage.Enabled | bool | `true` | | | config.LocalStorage.Location | string | `"./chronicle-data"` | | | config.LocalStorage.RetentionPeriod | string | `"30d"` | | | config.Logging.ServiceLog | string | `"STDOUT"` | | @@ -175,7 +179,7 @@ The credentials Chronicle uses for S3 storage must have the following permission | config.S3Storage.Region | string | `"us-east-2"` | | | image.imagePullPolicy | string | `"IfNotPresent"` | | | image.repository | string | `"ghcr.io/rstudio/chronicle"` | | -| image.tag | string | `"2024.03.0"` | | +| image.tag | string | `"2024.11.0"` | | | nodeSelector | object | `{}` | A map used verbatim as the pod's "nodeSelector" definition | | pod.affinity | object | `{}` | A map used verbatim as the pod's "affinity" definition | | pod.annotations | object | `{}` | Additional annotations to add to the chronicle-server pods | @@ -199,5 +203,5 @@ The credentials Chronicle uses for S3 storage must have the following permission | storage.persistentVolumeSize | string | `"1Gi"` | | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0) +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/charts/posit-chronicle/README.md.gotmpl b/charts/posit-chronicle/README.md.gotmpl index 3681e788..4c87890d 100644 --- a/charts/posit-chronicle/README.md.gotmpl +++ b/charts/posit-chronicle/README.md.gotmpl @@ -30,7 +30,7 @@ pod: mountPath: "/var/lib/rstudio-server/audit" sidecar: - name: chronicle-agent - image: ghcr.io/rstudio/chronicle-agent:2024.03.0 + image: ghcr.io/rstudio/chronicle-agent:2024.11.0 volumeMounts: - name: logs mountPath: "/var/lib/rstudio-server/audit" @@ -46,7 +46,7 @@ API key from a Kubernetes Secret is used to unlock more detailed metrics: pod: sidecar: - name: chronicle-agent - image: ghcr.io/rstudio/chronicle-agent:2024.03.0 + image: ghcr.io/rstudio/chronicle-agent:2024.11.0 env: - name: CHRONICLE_SERVER_ADDRESS value: "http://chronicle-server.default" diff --git a/charts/posit-chronicle/values.yaml b/charts/posit-chronicle/values.yaml index 9d747ba8..d81bce11 100644 --- a/charts/posit-chronicle/values.yaml +++ b/charts/posit-chronicle/values.yaml @@ -1,6 +1,6 @@ image: repository: "ghcr.io/rstudio/chronicle" - tag: "2024.03.0" + tag: "2024.11.0" imagePullPolicy: "IfNotPresent" serviceaccount: @@ -70,9 +70,8 @@ config: ServiceLogLevel: "INFO" ServiceLogFormat: "TEXT" LocalStorage: - # By default when localStorage.enabled=false, the chronicle stateful-set - # won't submit a volume claim or be bound to a persistent volume - Enabled: false + # By default LocalStorage.Enabled=true, so that installs work with the default values + Enabled: true Location: "./chronicle-data" RetentionPeriod: "30d" S3Storage: diff --git a/charts/rstudio-connect/.helmignore b/charts/rstudio-connect/.helmignore new file mode 100644 index 00000000..f70705f1 --- /dev/null +++ b/charts/rstudio-connect/.helmignore @@ -0,0 +1,26 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ + +# chart tests +tests/ diff --git a/charts/rstudio-connect/Chart.lock b/charts/rstudio-connect/Chart.lock index 9ebc104b..9b57df62 100644 --- a/charts/rstudio-connect/Chart.lock +++ b/charts/rstudio-connect/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: rstudio-library - repository: file://../rstudio-library - version: 0.1.29 -digest: sha256:ccca30d883d295668402d63328b1d603911ef717b41207f9b3a2e4d1dd3af1a3 -generated: "2024-04-01T12:17:53.025791-04:00" + repository: https://helm.rstudio.com + version: 0.1.31 +digest: sha256:2a0e98b8fa01730bf2db3816a7310462c921b9fa2f1f3c74f85fedede82e1593 +generated: "2024-11-01T10:19:53.608088-04:00" diff --git a/charts/rstudio-connect/Chart.yaml b/charts/rstudio-connect/Chart.yaml index 225d2322..09f273d4 100644 --- a/charts/rstudio-connect/Chart.yaml +++ b/charts/rstudio-connect/Chart.yaml @@ -1,8 +1,8 @@ name: rstudio-connect -description: Official Helm chart for RStudio Connect -version: 0.6.6 +description: Official Helm chart for Posit Connect +version: 0.7.18 apiVersion: v2 -appVersion: 2024.04.1 +appVersion: 2024.12.0 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png home: https://www.rstudio.com sources: @@ -13,12 +13,12 @@ maintainers: url: https://github.com/sol-eng dependencies: - name: rstudio-library - version: 0.1.29 - repository: file://../rstudio-library + version: 0.1.31 + repository: https://helm.rstudio.com annotations: artifacthub.io/images: | - name: rstudio-connect - image: rstudio/rstudio-connect:ubuntu2204-2024.04.1 + image: rstudio/rstudio-connect:ubuntu2204-2024.12.0 artifacthub.io/license: MIT artifacthub.io/links: | - name: Docker Images diff --git a/charts/rstudio-connect/NEWS.md b/charts/rstudio-connect/NEWS.md index 36f8c37d..310b5c6e 100644 --- a/charts/rstudio-connect/NEWS.md +++ b/charts/rstudio-connect/NEWS.md @@ -1,6 +1,99 @@ # Changelog -# 0.6.6 +## 0.7.18 + +- Bumps Connect version to 2024.12.0 + +## 0.7.17 + +- Bump Chronicle Agent to version 2024.11.0 + +## 0.7.16 + +- Change location of helm unittests to `ci/rstudio-connect/tests` so changes to unittest files do not require a chart version bump + +## 0.7.15 + +- Bump Connect version to 2024.11.0 + +## 0.7.14 + +- Pin the rstudio-library version dependency so we can update the library chart without breaking all the charts that depend on it. + +## 0.7.13 + +- Add initial set of helm unit tests. + +## 0.7.12 + +- Fix a bug where `rbac.serviceAccount.name` was not applied when the job launcher is enabled. + +## 0.7.11 + +- Move the values files for linting and installation testing outside the chart directory so that we can iterate on them without releasing a new version of the chart + +## 0.7.10 + +- Bump version of launcher templates `job.tpl` and `service.tpl` + - `enableServiceLinks` now defaults to `false` for sessions (instead of not being set). + To enable them for sessions, set `launcher.templateValues.enableServiceLinks: true`. + - Also see related discussion [on the Kubernetes project](https://github.com/kubernetes/kubernetes/issues/121787) +- Removed a protection against `.resources.enabled = false` which was a [bad attempt at backwards compatibility two + years ago](https://github.com/rstudio/helm/pull/224) (v0.2.34) + +## 0.7.9 + +- Bump Connect version to 2024.09.0 + +## 0.7.8 + +- Bump Chronicle Agent to version 2024.09.0 + +## 0.7.7 + +- Add helm values for `pod.hostAliases` and `launcher.templateValues.pod.hostAliases` +- Add helm values for `launcher.defaultInitContainer.resources` + +## 0.7.6 + +- Bump Connect version to 2024.08.0 + +## 0.7.4 + +- BREAKING: local execution only + - Default installed Quarto version upgraded to 1.4.557 + +## 0.7.3 + +- Bump Connect version to 2024.06.0 + +## 0.7.2 + +- Bump Connect version to 2024.05.0 +- BREAKING: local execution only + - Default installed R versions upgraded to 4.4.0 and 4.3.3. + - Default installed Python versions upgraded to 3.12.1 and 3.11.7. +- Enable TensorFlow by default in `values.yaml` when running in local or + off-host execution mode. + +## 0.7.1 + +- Add documentation about PostgreSQL database configuration and mounting passwords from secrets as env variables + +## 0.7.0 + +- BREAKING: the prometheus endpoint has changed from port `9108` to `3232` by default + - We are now using an internal prometheus endpoint with all new metrics + - As a result, the `graphiteExporter` sidecar has been removed + - Some metrics from the `graphiteExporter` will no longer be present + - The parent / main "off-switch" for prometheus is at `prometheus.enabled` + - To revert to the old exporter, set `prometheus.legacy=true` (and please reach out to let us know why!) + +## 0.6.7 + +- Documentation site updates + +## 0.6.6 - Bump Connect version to 2024.04.1 diff --git a/charts/rstudio-connect/README.md b/charts/rstudio-connect/README.md index a44de207..5c4502f8 100644 --- a/charts/rstudio-connect/README.md +++ b/charts/rstudio-connect/README.md @@ -1,67 +1,73 @@ # Posit Connect -![Version: 0.6.6](https://img.shields.io/badge/Version-0.6.6-informational?style=flat-square) ![AppVersion: 2024.04.1](https://img.shields.io/badge/AppVersion-2024.04.1-informational?style=flat-square) +![Version: 0.7.18](https://img.shields.io/badge/Version-0.7.18-informational?style=flat-square) ![AppVersion: 2024.12.0](https://img.shields.io/badge/AppVersion-2024.12.0-informational?style=flat-square) -#### _Official Helm chart for RStudio Connect_ +#### _Official Helm chart for Posit Connect_ Business Users and Collaborators use R and Python data products on [Posit Connect](https://posit.co/products/enterprise/connect/) that are published by Data Scientists. -## Best Practices +## Best practices Helm charts are very useful tools for deploying resources into Kubernetes, however, they do require some familiarity with kubernetes and `helm` itself. Please ensure you have adequate training and IT support before deploying these charts into production environments. Reach out to your account representative -if you need help deciding whether helm is a good choice for your deployment. +if you need help deciding whether Helm is a good choice for your deployment. To ensure reproducibility in your environment and insulate yourself from future changes, please: -* Ensure you "pin" the version of the Helm chart that you are using. You can do - this using the `helm dependency` command and the associated "Chart.lock" files - or the `--version` flag. **IMPORTANT: This protects you from breaking changes** -* Before upgrading, to avoid breaking changes, use the `helm-diff` plugin and `helm diff upgrade` to check - for breaking changes -* Read [`NEWS.md`](./NEWS.md) for updates on breaking - changes, as well as documentation below on how to use the chart +* "Pin" the version of the Helm chart that you are using. You can do + this using the: + * `helm dependency` command and the associated "Chart.lock" files _or_ + * the `--version` flag. -## Installing the Chart + :::{.callout-important} + This protects you from breaking changes** + ::: -To install the chart with the release name `my-release` at version 0.6.6: +* Before upgrading check for breaking changes using `helm-diff` plugin and `helm diff upgrade`. +* Read [`NEWS.md`](./NEWS.md) for updates on breaking changes and the documentation below on how to use the chart. -```bash +## Installing the chart + +To install the chart with the release name `my-release` at version 0.7.18: + +```{.bash} helm repo add rstudio https://helm.rstudio.com -helm upgrade --install my-release rstudio/rstudio-connect --version=0.6.6 +helm upgrade --install my-release rstudio/rstudio-connect --version=0.7.18 ``` -To explore other chart versions, take a look at: -``` +To explore other chart versions, look at: + +```{.bash} helm search repo rstudio/rstudio-connect -l ``` -## Required Configuration +## Required configuration -This chart requires the following in order to function: +To function, this chart requires the following: -* A license file, license key, or address of a running license server. See the [Licensing](#licensing) section below for more details. +* A license file. See the [Licensing](#licensing) section below for more details. * A Kubernetes [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) that contains the data directory for Connect. - * If `sharedStorage.create` is set, a PVC that relies on the default storage class will be created to generate the PersistentVolume. + * If `sharedStorage.create` is set, it creates a Persistent Volume Claim (PVC) that relies on the default storage class to generate the + PersistentVolume. Most Kubernetes environments do not have a default storage class that you can use with `ReadWriteMany` access mode out-of-the-box. In this case, we recommend you disable `sharedStorage.create` and create your own `PersistentVolume` and `PersistentVolumeClaim`, then mount them into the container by specifying the `pod.volumes` and `pod.volumeMounts` parameters, or by specifying your `PersistentVolumeClaim` using `sharedStorage.name` and `sharedStorage.mount`. - * If you cannot use a `PersistentVolume` to properly mount your data directory, you'll need to mount your data in the container + * If you cannot use a `PersistentVolume` to properly mount your data directory, mount your data in the container by using a regular [Kubernetes Volume](https://kubernetes.io/docs/concepts/storage/volumes), specified in `pod.volumes` and `pod.volumeMounts`. ## Licensing -This chart supports activating the product using a license file, license key, or license server. In the case of a license file or key, we recommend against placing it in your values file directly. - -### License File +This chart supports activating the product using a *license file*. We recommend storing a license file as a `Secret` and setting the `license.file.secret` and `license.file.secretKey` values accordingly. First, create the secret declaratively with YAML or imperatively using the following command: -`kubectl create secret generic rstudio-connect-license --from-file=licenses/rstudio-connect.lic` +```{.bash} +kubectl create secret generic rstudio-connect-license --from-file=licenses/rstudio-connect.lic +``` Second, specify the following values: @@ -74,29 +80,63 @@ license: Alternatively, license files can be set during `helm install` with the following argument: -`--set-file license.file.contents=licenses/rstudio-connect.lic` +```{.bash} +--set-file license.file.contents=licenses/rstudio-connect.lic +``` + +## Database -### License Key +Connect requires a PostgreSQL database when running in Kubernetes. You must configure a [valid connection URI and a password](https://docs.posit.co/connect/admin/database/postgres/) for the product to function correctly. Both the connection URI and password may be specified in the `config` section of `values.yaml`. However, we recommend only adding the connection URI and putting the database password in a Kubernetes `Secret`, which can be [automatically set as an environment variable](#database-password). -Set a license key directly in your values file (`license.key`) or during `helm install` with the argument `--set license.key=XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX`. +### Database configuration -### License Server +Add the following to your `values.yaml`, replacing the `URL` with your database details. + +```yaml +config: + Database: + Provider: "Postgres" + Postgres: + URL: "postgres://@:/" +``` -Set a license server directly in your values file (`license.server`) or during `helm install` with the argument `--set license.server=`. +### Database password -## General Principles +First, create a `Secret` declaratively with YAML or imperatively using the following command (replacing with your actual password): -- In most places, we opt to pass helm values over configmaps. We translate these into the valid `.gcfg` file format +```bash +kubectl create secret generic rstudio-connect-database --from-literal=password=YOURPASSWORDHERE +``` + +Second, specify the following in your `values.yaml`: + +```yaml +pod: + env: + - name: CONNECT_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: rstudio-connect-database + key: password +``` + +Alternatively, database passwords may be set during `helm install` with the following argument: + +`--set config.Postgres.Password=""` + +## General principles + +- In most places, we opt to pass Helm values over configmaps. We translate these into the valid `.gcfg` file format required by rstudio-connect. - rstudio-connect does not export many prometheus metrics on its own. Instead, we run a sidecar graphite exporter [as described here](https://support.rstudio.com/hc/en-us/articles/360044800273-Monitoring-RStudio-Team-Using-Prometheus-and-Graphite) -## Configuration File +## Configuration file -The configuration values all take the form of usual helm values +The configuration values all take the form of usual Helm values so you can set the database password with something like: -``` +```{.bash} ... --set config.Postgres.Password=mypassword ... ``` @@ -126,10 +166,11 @@ The Helm `config` values are converted into the `rstudio-connect.gcfg` service c | initContainers | bool | `false` | The initContainer spec that will be used verbatim | | launcher.additionalRuntimeImages | list | `[]` | Optional. Additional images to append to the end of the "launcher.customRuntimeYaml" (in the "images" key). If `customRuntimeYaml` is a "map", then "additionalRuntimeImages" will only be used if it is a "list". | | launcher.customRuntimeYaml | string | `"base"` | Optional. The runtime.yaml definition of Kubernetes runtime containers. Defaults to "base", which pulls in the default runtime.yaml file. If changing this value, be careful to include the images that you have already used. If set to "pro", will pull in the "pro" versions of the default runtime images (i.e. including the pro drivers at the cost of a larger image). Starting with Connect v2023.05.0, this configuration is used to bootstrap the initial set of execution environments the first time the server starts. If any execution environments already exist in the database, these values are ignored; execution environments are not created or modified during subsequent restarts. | -| launcher.defaultInitContainer | object | `{"enabled":true,"imagePullPolicy":"","repository":"ghcr.io/rstudio/rstudio-connect-content-init","securityContext":{},"tag":"","tagPrefix":"ubuntu2204-"}` | Image definition for the default Posit Connect Content InitContainer | +| launcher.defaultInitContainer | object | `{"enabled":true,"imagePullPolicy":"","repository":"ghcr.io/rstudio/rstudio-connect-content-init","resources":{},"securityContext":{},"tag":"","tagPrefix":"ubuntu2204-"}` | Image definition for the default Posit Connect Content InitContainer | | launcher.defaultInitContainer.enabled | bool | `true` | Whether to enable the defaultInitContainer. If disabled, you must ensure that the session components are available another way. | | launcher.defaultInitContainer.imagePullPolicy | string | `""` | The imagePullPolicy for the default initContainer | | launcher.defaultInitContainer.repository | string | `"ghcr.io/rstudio/rstudio-connect-content-init"` | The repository to use for the Content InitContainer image | +| launcher.defaultInitContainer.resources | object | `{}` | Optional resources for the default initContainer | | launcher.defaultInitContainer.securityContext | object | `{}` | The securityContext for the default initContainer | | launcher.defaultInitContainer.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | | launcher.defaultInitContainer.tagPrefix | string | `"ubuntu2204-"` | A tag prefix for the Content InitContainer image (common selections: jammy-, ubuntu2204-). Only used if tag is not defined | @@ -139,13 +180,13 @@ The Helm `config` values are converted into the `rstudio-connect.gcfg` service c | launcher.includeTemplateValues | bool | `true` | whether to include the templateValues rendering process | | launcher.launcherKubernetesProfilesConf | object | `{}` | User definition of launcher.kubernetes.profiles.conf for job customization | | launcher.namespace | string | `""` | The namespace to launch sessions into. Uses the Release namespace by default | -| launcher.templateValues | object | `{"job":{"annotations":{},"labels":{}},"pod":{"affinity":{},"annotations":{},"command":[],"containerSecurityContext":{},"defaultSecurityContext":{},"env":[],"extraContainers":[],"imagePullPolicy":"","imagePullSecrets":[],"initContainers":[],"labels":{},"nodeSelector":{},"priorityClassName":"","securityContext":{},"serviceAccountName":"","tolerations":[],"volumeMounts":[],"volumes":[]},"service":{"annotations":{},"labels":{},"type":"ClusterIP"}}` | Values to pass along to the Posit Connect session templating process | +| launcher.templateValues | object | `{"job":{"annotations":{},"labels":{}},"pod":{"affinity":{},"annotations":{},"command":[],"containerSecurityContext":{},"defaultSecurityContext":{},"env":[],"extraContainers":[],"hostAliases":[],"imagePullPolicy":"","imagePullSecrets":[],"initContainers":[],"labels":{},"nodeSelector":{},"priorityClassName":"","securityContext":{},"serviceAccountName":"","tolerations":[],"volumeMounts":[],"volumes":[]},"service":{"annotations":{},"labels":{},"type":"ClusterIP"}}` | Values to pass along to the Posit Connect session templating process | | launcher.templateValues.pod.command | list | `[]` | command for all pods. This is really not something we should expose and will be removed once we have a better option | | launcher.useTemplates | bool | `true` | Whether to use launcher templates when launching sessions. Defaults to true | | license.file | object | `{"contents":false,"mountPath":"/etc/rstudio-licensing","mountSubPath":false,"secret":false,"secretKey":"license.lic"}` | the file section is used for licensing with a license file | | license.file.contents | bool | `false` | contents is an in-line license file | | license.file.mountPath | string | `"/etc/rstudio-licensing"` | mountPath is the place the license file will be mounted into the container | -| license.file.mountSubPath | bool | `false` | mountSubPath is whether to mount the subPath for the file secret. -- It can be preferable _not_ to enable this, because then updates propagate automatically | +| license.file.mountSubPath | bool | `false` | It can be preferable _not_ to enable this, because then updates propagate automatically | | license.file.secret | bool | `false` | secret is an existing secret with a license file in it | | license.file.secretKey | string | `"license.lic"` | secretKey is the key for the secret to use for the license file | | license.key | string | `nil` | key is the license to use | @@ -157,6 +198,7 @@ The Helm `config` values are converted into the `rstudio-connect.gcfg` service c | pod.annotations | object | `{}` | Additional annotations to add to the rstudio-connect pods | | pod.env | list | `[]` | An array of maps that is injected as-is into the "env:" component of the pod.container spec | | pod.haste | bool | `true` | A helper that defines the RSTUDIO_CONNECT_HASTE environment variable | +| pod.hostAliases | list | `[]` | Array of hostnames to supply to the main pod | | pod.labels | object | `{}` | Additional labels to add to the rstudio-connect pods | | pod.port | int | `3939` | The containerPort used by the main pod container | | pod.securityContext | object | `{}` | Values to set the `securityContext` for the connect pod | @@ -166,7 +208,10 @@ The Helm `config` values are converted into the `rstudio-connect.gcfg` service c | pod.volumes | list | `[]` | An array of maps that is injected as-is into the "volumes:" component of the pod spec | | podDisruptionBudget | object | `{}` | Pod disruption budget | | priorityClassName | string | `""` | The pod's priorityClassName | -| prometheusExporter.enabled | bool | `true` | Whether the prometheus exporter sidecar should be enabled | +| prometheus.enabled | bool | `true` | The parent setting for whether to enable prometheus metrics. Default is to use the built-in product exporter | +| prometheus.legacy | bool | `false` | Whether to enable the legacy prometheusExporter INSTEAD OF the built-in product exporter. If you change this to `true`, please let us know why! Requires prometheusExporter.enabled=true too | +| prometheus.port | int | `3232` | The port that prometheus will listen on. If legacy=true, then this will be hard-coded to 9108 | +| prometheusExporter.enabled | bool | `true` | DEPRECATED. Whether the prometheus exporter sidecar should be enabled. See prometheus.enabled instead. | | prometheusExporter.image.imagePullPolicy | string | `"IfNotPresent"` | | | prometheusExporter.image.repository | string | `"prom/graphite-exporter"` | | | prometheusExporter.image.tag | string | `"v0.9.0"` | | @@ -210,5 +255,5 @@ The Helm `config` values are converted into the `rstudio-connect.gcfg` service c | versionOverride | string | `""` | A Connect version to override the "tag" for the Posit Connect image and the Content Init image. Necessary until https://github.com/helm/helm/issues/8194 | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0) +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/charts/rstudio-connect/README.md.gotmpl b/charts/rstudio-connect/README.md.gotmpl index 3906063a..0e4d96e4 100644 --- a/charts/rstudio-connect/README.md.gotmpl +++ b/charts/rstudio-connect/README.md.gotmpl @@ -8,34 +8,75 @@ {{ template "rstudio.install" . }} -## Required Configuration +## Required configuration -This chart requires the following in order to function: +To function, this chart requires the following: -* A license file, license key, or address of a running license server. See the [Licensing](#licensing) section below for more details. +* A license file. See the [Licensing](#licensing) section below for more details. * A Kubernetes [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) that contains the data directory for Connect. - * If `sharedStorage.create` is set, a PVC that relies on the default storage class will be created to generate the PersistentVolume. + * If `sharedStorage.create` is set, it creates a Persistent Volume Claim (PVC) that relies on the default storage class to generate the + PersistentVolume. Most Kubernetes environments do not have a default storage class that you can use with `ReadWriteMany` access mode out-of-the-box. In this case, we recommend you disable `sharedStorage.create` and create your own `PersistentVolume` and `PersistentVolumeClaim`, then mount them into the container by specifying the `pod.volumes` and `pod.volumeMounts` parameters, or by specifying your `PersistentVolumeClaim` using `sharedStorage.name` and `sharedStorage.mount`. - * If you cannot use a `PersistentVolume` to properly mount your data directory, you'll need to mount your data in the container + * If you cannot use a `PersistentVolume` to properly mount your data directory, mount your data in the container by using a regular [Kubernetes Volume](https://kubernetes.io/docs/concepts/storage/volumes), specified in `pod.volumes` and `pod.volumeMounts`. {{ template "rstudio.licensing" . }} -## General Principles +## Database -- In most places, we opt to pass helm values over configmaps. We translate these into the valid `.gcfg` file format +Connect requires a PostgreSQL database when running in Kubernetes. You must configure a [valid connection URI and a password](https://docs.posit.co/connect/admin/database/postgres/) for the product to function correctly. Both the connection URI and password may be specified in the `config` section of `values.yaml`. However, we recommend only adding the connection URI and putting the database password in a Kubernetes `Secret`, which can be [automatically set as an environment variable](#database-password). + +### Database configuration + +Add the following to your `values.yaml`, replacing the `URL` with your database details. + +```yaml +config: + Database: + Provider: "Postgres" + Postgres: + URL: "postgres://@:/" +``` + +### Database password + +First, create a `Secret` declaratively with YAML or imperatively using the following command (replacing with your actual password): + +```bash +kubectl create secret generic {{ .Name }}-database --from-literal=password=YOURPASSWORDHERE +``` + +Second, specify the following in your `values.yaml`: + +```yaml +pod: + env: + - name: CONNECT_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Name }}-database + key: password +``` + +Alternatively, database passwords may be set during `helm install` with the following argument: + +`--set config.Postgres.Password=""` + +## General principles + +- In most places, we opt to pass Helm values over configmaps. We translate these into the valid `.gcfg` file format required by {{ template "chart.name" . }}. - {{ template "chart.name" . }} does not export many prometheus metrics on its own. Instead, we run a sidecar graphite exporter [as described here](https://support.rstudio.com/hc/en-us/articles/360044800273-Monitoring-RStudio-Team-Using-Prometheus-and-Graphite) -## Configuration File +## Configuration file -The configuration values all take the form of usual helm values +The configuration values all take the form of usual Helm values so you can set the database password with something like: -``` +```{.bash} ... --set config.Postgres.Password=mypassword ... ``` diff --git a/charts/rstudio-connect/files/job.tpl b/charts/rstudio-connect/files/job.tpl index c8279a75..4a87c105 100644 --- a/charts/rstudio-connect/files/job.tpl +++ b/charts/rstudio-connect/files/job.tpl @@ -1,6 +1,6 @@ -# Version: 2.3.1 +# Version: 2.4.0 # DO NOT MODIFY the "Version: " key -# Helm Version: v3 +# Helm Version: v1 {{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} apiVersion: batch/v1 kind: Job @@ -18,6 +18,9 @@ metadata: {{- end }} labels: app.kubernetes.io/managed-by: "launcher" + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} {{- with .Job.metadata.job.labels }} {{- range $key, $val := . }} {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} @@ -30,6 +33,9 @@ metadata: {{- end }} generateName: {{ toYaml .Job.generateName }} spec: + {{- if $templateData.job.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ $templateData.job.ttlSecondsAfterFinished }} + {{- end }} backoffLimit: 0 template: metadata: @@ -59,6 +65,9 @@ spec: {{- end }} {{- end }} labels: + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} {{- with .Job.metadata.pod.labels }} {{- range $key, $val := . }} {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} @@ -74,10 +83,15 @@ spec: {{- if .Job.host }} nodeName: {{ toYaml .Job.host }} {{- end }} + enableServiceLinks: {{ if hasKey $templateData.pod "enableServiceLinks" }}{{ $templateData.pod.enableServiceLinks }}{{ else }}false{{ end }} restartPolicy: Never {{- if or $templateData.pod.serviceAccountName .Job.serviceAccountName }} serviceAccountName: {{ .Job.serviceAccountName | default $templateData.pod.serviceAccountName | quote }} {{- end }} + {{- with $templateData.pod.hostAliases }} + hostAliases: + {{- toYaml . | nindent 8 }} + {{- end }} shareProcessNamespace: {{ .Job.shareProcessNamespace }} {{- if or (ne (len .Job.volumes) 0) (ne (len $templateData.pod.volumes) 0) }} volumes: @@ -96,7 +110,7 @@ spec: affinity: {{- toYaml . | nindent 8 }} {{- end }} - {{- if or (ne (len .Job.placementConstraints) 0) (ne (len $templateData.pod.nodeSelector) 0) }} + {{- if or (ne (len .Job.placementConstraints) 0) (and $templateData.pod.nodeSelector (ne (len $templateData.pod.nodeSelector) 0)) }} nodeSelector: {{- range .Job.placementConstraints }} {{ .name }}: {{ toYaml .value }} diff --git a/charts/rstudio-connect/files/service.tpl b/charts/rstudio-connect/files/service.tpl index f2b506ae..30bfca27 100644 --- a/charts/rstudio-connect/files/service.tpl +++ b/charts/rstudio-connect/files/service.tpl @@ -1,6 +1,6 @@ -# Version: 2.3.1 +# Version: 2.4.0 # DO NOT MODIFY the "Version: " key -# Helm Version: v3 +# Helm Version: v1 {{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} apiVersion: v1 kind: Service @@ -20,6 +20,9 @@ metadata: labels: app.kubernetes.io/managed-by: "launcher" job-name: {{ toYaml .Job.id }} + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} {{- with .Job.metadata.service.labels }} {{- range $key, $val := . }} {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} diff --git a/charts/rstudio-connect/templates/NOTES.txt b/charts/rstudio-connect/templates/NOTES.txt index fc3d2dc8..e16b7318 100644 --- a/charts/rstudio-connect/templates/NOTES.txt +++ b/charts/rstudio-connect/templates/NOTES.txt @@ -61,3 +61,9 @@ Please consider removing this configuration value. {{- fail "\n\n`pod.nodeSelector` is no longer used. Use `nodeSelector` instead!\nThis is more consistent with other charts and the community." }} {{- end }} + +{{- if and (hasKey .Values.config.Metrics "GraphiteEnabled") (not .Values.prometheus.legacy) }} + +{{- print "\n\n`config.Metrics.GraphiteEnabled` is overwritten by `prometheus.legacy=false`. Internal Connect Prometheus will be used instead." }} + +{{- end }} diff --git a/charts/rstudio-connect/templates/_helpers.tpl b/charts/rstudio-connect/templates/_helpers.tpl index 59e75091..ffe45fcf 100644 --- a/charts/rstudio-connect/templates/_helpers.tpl +++ b/charts/rstudio-connect/templates/_helpers.tpl @@ -57,6 +57,7 @@ app.kubernetes.io/instance: {{ .Release.Name }} - set launcher parameters if applicable */}} {{- define "rstudio-connect.config" -}} + {{- $configCopy := deepCopy .Values.config }} {{- $defaultConfig := dict }} {{- /* default launcher configuration */}} {{- if .Values.launcher.enabled }} @@ -80,7 +81,26 @@ app.kubernetes.io/instance: {{ .Release.Name }} {{- $licenseDict := dict "Licensing" ( dict "LicenseType" ("Remote") ) }} {{- $defaultConfig = merge $defaultConfig $licenseDict }} {{- end }} - {{- include "rstudio-library.config.gcfg" ( mergeOverwrite $defaultConfig .Values.config ) }} + {{- /* default metrics / prometheus configuration */}} + {{- if .Values.prometheus.enabled }} + {{- if .Values.prometheus.legacy }} + {{- /* we set the graphite values as a default, to hide from values.yaml */ -}} + {{- $graphiteDict := dict "Metrics" (dict "Enabled" true "GraphiteClientId" "rsconnect" "GraphiteEnabled" true) }} + {{- $graphiteDict = merge $graphiteDict (dict "Metrics" (dict "GraphiteHost" "127.0.0.1" "GraphitePort" "9109")) }} + {{- $defaultConfig = merge $defaultConfig $graphiteDict }} + {{- else }} + {{- if hasKey $configCopy "Metrics" }} + {{- if hasKey (get $configCopy "Metrics") "GraphiteEnabled" }} + {{- /* we explicitly overwrite the graphite endpoint */ -}} + {{- mergeOverwrite $configCopy (dict "Metrics" (dict "GraphiteEnabled" false))}} + {{- end }} + {{- end }} + + {{- /* and set a default for the prometheus listener */ -}} + {{- $defaultConfig = merge $defaultConfig (dict "Metrics" ( dict "PrometheusListen" (print ":" .Values.prometheus.port )))}} + {{- end }} + {{- end }} + {{- include "rstudio-library.config.gcfg" ( mergeOverwrite $defaultConfig $configCopy ) }} {{- end -}} {{/* diff --git a/charts/rstudio-connect/templates/configmap-graphite-exporter.yaml b/charts/rstudio-connect/templates/configmap-graphite-exporter.yaml index e55e9330..3e981e73 100644 --- a/charts/rstudio-connect/templates/configmap-graphite-exporter.yaml +++ b/charts/rstudio-connect/templates/configmap-graphite-exporter.yaml @@ -1,4 +1,4 @@ -{{- if .Values.prometheusExporter.enabled }} +{{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} --- apiVersion: v1 kind: ConfigMap diff --git a/charts/rstudio-connect/templates/configmap.yaml b/charts/rstudio-connect/templates/configmap.yaml index bb14f55f..5dcab04d 100644 --- a/charts/rstudio-connect/templates/configmap.yaml +++ b/charts/rstudio-connect/templates/configmap.yaml @@ -23,9 +23,10 @@ data: {{- $initContainerImageTag := .Values.launcher.defaultInitContainer.tag | default (printf "%s%s" .Values.launcher.defaultInitContainer.tagPrefix $defaultVersion )}} {{- $initContainerImage := print .Values.launcher.defaultInitContainer.repository ":" ( $initContainerImageTag ) }} {{- $initContainerPullPolicy := default "IfNotPresent" .Values.launcher.defaultInitContainer.imagePullPolicy }} + {{- $initContainerResources := .Values.launcher.defaultInitContainer.resources }} {{- $initContainerSecurityContext := .Values.launcher.defaultInitContainer.securityContext }} {{- $initContainerVolumeMount := dict "name" ("rsc-volume") "mountPath" ("/mnt/rstudio-connect-runtime/") }} - {{- $initContainerJson := dict "name" ("init") "image" ($initContainerImage) "imagePullPolicy" ($initContainerPullPolicy) "volumeMounts" ( list $initContainerVolumeMount ) "securityContext" $initContainerSecurityContext }} + {{- $initContainerJson := dict "name" ("init") "image" ($initContainerImage) "imagePullPolicy" ($initContainerPullPolicy) "resources" ($initContainerResources) "volumeMounts" ( list $initContainerVolumeMount ) "securityContext" $initContainerSecurityContext }} {{- $jobJsonInitContainer := dict "target" ("/spec/template/spec/initContainers/0") "name" ("defaultInitContainer") "json" $initContainerJson }} {{- /* set up job-json defaults */ -}} {{- $jobJsonDefaults := list }} diff --git a/charts/rstudio-connect/templates/deployment.yaml b/charts/rstudio-connect/templates/deployment.yaml index fecd7c58..e5b9a625 100644 --- a/charts/rstudio-connect/templates/deployment.yaml +++ b/charts/rstudio-connect/templates/deployment.yaml @@ -20,14 +20,20 @@ spec: metadata: annotations: checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} checksum/config-graphite: {{ include (print $.Template.BasePath "/configmap-graphite-exporter.yaml") . | sha256sum }} + {{- end }} {{- if .Values.launcher.enabled }} checksum/config-prestart: {{ include (print $.Template.BasePath "/configmap-prestart.yaml") . | sha256sum }} {{- end }} - {{- if .Values.prometheusExporter.enabled }} + {{- if .Values.prometheus }} prometheus.io/scrape: "true" prometheus.io/path: "/metrics" + {{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} prometheus.io/port: "9108" + {{- else }} + prometheus.io/port: {{ .Values.prometheus.port | quote }} + {{- end }} {{- end }} {{ include "rstudio-connect.pod.annotations" . | indent 8 }} labels: @@ -40,6 +46,10 @@ spec: affinity: {{- toYaml . | nindent 8 }} {{- end }} + {{- with .Values.pod.hostAliases }} + hostAliases: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -67,7 +77,7 @@ spec: * https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-multiple-service-accounts */}} {{- if and .Values.rbac.create .Values.launcher.enabled }} - {{ $serviceAccountName := default (default .Values.rbac.serviceAccount.name .Values.pod.serviceAccountName) (include "rstudio-connect.fullname" .) }} + {{ $serviceAccountName := default (include "rstudio-connect.fullname" .) .Values.rbac.serviceAccount.name }} serviceAccountName: {{ $serviceAccountName }} {{- else }} serviceAccountName: {{ .Values.rbac.serviceAccount.name | toString | quote }} @@ -118,6 +128,11 @@ spec: imagePullPolicy: "{{ .Values.image.imagePullPolicy }}" ports: - containerPort: {{ .Values.pod.port }} + name: http + {{- if and .Values.prometheus.enabled (not .Values.prometheus.legacy) }} + - containerPort: {{ .Values.prometheus.port }} + name: metrics + {{- end}} {{- with .Values.securityContext }} securityContext: {{- toYaml . | nindent 10 }} @@ -160,11 +175,11 @@ spec: {{- end }} {{ include "rstudio-library.license-mount" (dict "license" ( .Values.license )) | indent 10 }} {{- if .Values.pod.volumeMounts }} -{{ toYaml .Values.pod.volumeMounts | indent 10 }} + {{- toYaml .Values.pod.volumeMounts | nindent 10 }} {{- end }} {{- with .Values.resources }} resources: - {{ toYaml (omit . "enabled") | nindent 10 }} + {{- toYaml . | nindent 10 }} {{- end }} {{- if .Values.livenessProbe.enabled }} {{- $liveness := omit .Values.livenessProbe "enabled" }} @@ -187,7 +202,7 @@ spec: {{- toYaml . | nindent 10 }} {{- end }} {{- end }} - {{- if .Values.prometheusExporter.enabled }} + {{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} - name: exporter image: "{{ .Values.prometheusExporter.image.repository }}:{{ .Values.prometheusExporter.image.tag }}" imagePullPolicy: "{{ .Values.prometheusExporter.image.imagePullPolicy }}" @@ -220,7 +235,7 @@ spec: claimName: {{default (print (include "rstudio-connect.fullname" .) "-shared-storage" ) .Values.sharedStorage.name }} {{- end }} {{ include "rstudio-library.license-volume" (dict "license" ( .Values.license ) "fullName" (include "rstudio-connect.fullname" .)) | indent 6 }} - {{- if .Values.prometheusExporter.enabled }} + {{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} - name: graphite-exporter-config configMap: name: {{ include "rstudio-connect.fullname" . }}-graphite diff --git a/charts/rstudio-connect/templates/rbac.yaml b/charts/rstudio-connect/templates/rbac.yaml index acd31626..bfb25325 100644 --- a/charts/rstudio-connect/templates/rbac.yaml +++ b/charts/rstudio-connect/templates/rbac.yaml @@ -1,7 +1,7 @@ {{- if and (.Values.rbac.create) (.Values.launcher.enabled) }} {{ $namespace := $.Release.Namespace }} {{ $targetNamespace := default $.Release.Namespace .Values.launcher.namespace }} -{{ $serviceAccountName := default .Values.rbac.serviceAccount.name (include "rstudio-connect.fullname" .) }} +{{ $serviceAccountName := default (include "rstudio-connect.fullname" .) .Values.rbac.serviceAccount.name }} {{ $serviceAccountCreate := .Values.rbac.serviceAccount.create }} {{ $serviceAccountAnnotations := .Values.rbac.serviceAccount.annotations }} {{ $serviceAccountLabels := .Values.rbac.serviceAccount.labels }} diff --git a/charts/rstudio-connect/templates/service-monitor.yaml b/charts/rstudio-connect/templates/service-monitor.yaml index 7dab3edc..6907e474 100644 --- a/charts/rstudio-connect/templates/service-monitor.yaml +++ b/charts/rstudio-connect/templates/service-monitor.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.prometheusExporter.enabled .Values.serviceMonitor.enabled -}} +{{- if and .Values.prometheus.enabled .Values.serviceMonitor.enabled -}} apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: diff --git a/charts/rstudio-connect/templates/svc.yaml b/charts/rstudio-connect/templates/svc.yaml index 53ccfc0f..2190511a 100644 --- a/charts/rstudio-connect/templates/svc.yaml +++ b/charts/rstudio-connect/templates/svc.yaml @@ -17,7 +17,7 @@ spec: {{- end }} {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }} loadBalancerIP: {{ .Values.service.loadBalancerIP }} -{{- end }} +{{- end }} selector: {{- include "rstudio-connect.selectorLabels" . | nindent 4 }} ports: @@ -28,8 +28,13 @@ spec: nodePort: {{ .Values.service.nodePort }} {{- end }} targetPort: {{ .Values.service.targetPort }} - {{- if .Values.prometheusExporter.enabled }} + {{- if .Values.prometheus.enabled }} - name: metrics + targetPort: metrics + {{- if .Values.prometheus.legacy }} port: 9108 + {{- else }} + port: {{ .Values.prometheus.port }} + {{- end }} {{- end }} --- diff --git a/charts/rstudio-connect/values.yaml b/charts/rstudio-connect/values.yaml index 04128dc4..dc681601 100644 --- a/charts/rstudio-connect/values.yaml +++ b/charts/rstudio-connect/values.yaml @@ -127,6 +127,8 @@ pod: port: 3939 # -- The termination grace period seconds allowed for the pod before shutdown terminationGracePeriodSeconds: 120 + # -- Array of hostnames to supply to the main pod + hostAliases: [] # -- The pod's run command. By default, it uses the container's default command: [] @@ -159,8 +161,17 @@ license: securityContext: privileged: true +prometheus: + # -- The parent setting for whether to enable prometheus metrics. Default is to use the built-in product exporter + enabled: true + # -- The port that prometheus will listen on. If legacy=true, then this will be hard-coded to 9108 + port: 3232 + # -- Whether to enable the legacy prometheusExporter INSTEAD OF the built-in product exporter. If you change this to + # `true`, please let us know why! Requires prometheusExporter.enabled=true too + legacy: false + prometheusExporter: - # -- Whether the prometheus exporter sidecar should be enabled + # -- DEPRECATED. Whether the prometheus exporter sidecar should be enabled. See prometheus.enabled instead. enabled: true # -- Yaml that defines the graphite exporter mapping. null by default, which uses the embedded / default mapping yaml file mappingYaml: null @@ -298,6 +309,7 @@ launcher: tolerations: [] affinity: {} nodeSelector: {} + hostAliases: [] priorityClassName: "" # -- command for all pods. This is really not something we should expose and will be removed once we have a better option command: [] @@ -316,6 +328,14 @@ launcher: tag: "" # -- The imagePullPolicy for the default initContainer imagePullPolicy: "" + # -- Optional resources for the default initContainer + resources: {} + # requests: + # cpu: "128m" + # memory: "128Mi" + # limits: + # cpu: "512m" + # memory: "512Mi" # -- The securityContext for the default initContainer securityContext: {} @@ -339,14 +359,20 @@ config: # For Off-Host Execution, Python versions are defined by the set of Execution Environments # https://docs.posit.co/connect/admin/python/ Executable: - - /opt/python/3.9.17/bin/python - - /opt/python/3.8.17/bin/python + - /opt/python/3.12.1/bin/python + - /opt/python/3.11.7/bin/python Quarto: Enabled: true # Note: The `Executable` listed below is only used for Local Execution. # For Off-Host Execution, Quarto versions are defined by the set of Execution Environments # https://docs.posit.co/connect/admin/quarto/ - Executable: "/opt/quarto/1.4.552/bin/quarto" + Executable: "/opt/quarto/1.4.557/bin/quarto" + TensorFlow: + Enabled: true + # Note: The `Executable` listed below is only used for Local Execution. + # For Off-Host Execution, TensorFlow versions are defined by the set of Execution Environments + # https://docs.posit.co/connect/admin/tensorflow/ + Executable: "/usr/bin/tensorflow_model_server" Scheduler: InitTimeout: 5m Logging: @@ -357,7 +383,3 @@ config: AccessLogFormat: COMMON # COMMON, COMBINED, or JSON Metrics: Enabled: true - GraphiteEnabled: true - GraphiteHost: 127.0.0.1 - GraphitePort: 9109 - GraphiteClientId: rsconnect diff --git a/charts/rstudio-launcher-rbac/.helmignore b/charts/rstudio-launcher-rbac/.helmignore index 0e8a0eb3..f70705f1 100644 --- a/charts/rstudio-launcher-rbac/.helmignore +++ b/charts/rstudio-launcher-rbac/.helmignore @@ -21,3 +21,6 @@ .idea/ *.tmproj .vscode/ + +# chart tests +tests/ diff --git a/charts/rstudio-launcher-rbac/Chart.lock b/charts/rstudio-launcher-rbac/Chart.lock index 996a35e0..e02a858d 100644 --- a/charts/rstudio-launcher-rbac/Chart.lock +++ b/charts/rstudio-launcher-rbac/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: rstudio-library - repository: file://../rstudio-library - version: 0.1.29 -digest: sha256:ccca30d883d295668402d63328b1d603911ef717b41207f9b3a2e4d1dd3af1a3 -generated: "2024-04-01T12:17:21.579972-04:00" + repository: https://helm.rstudio.com + version: 0.1.31 +digest: sha256:2a0e98b8fa01730bf2db3816a7310462c921b9fa2f1f3c74f85fedede82e1593 +generated: "2024-11-01T10:21:05.638651-04:00" diff --git a/charts/rstudio-launcher-rbac/Chart.yaml b/charts/rstudio-launcher-rbac/Chart.yaml index d83849eb..e8d22b73 100644 --- a/charts/rstudio-launcher-rbac/Chart.yaml +++ b/charts/rstudio-launcher-rbac/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: rstudio-launcher-rbac description: RBAC definition for the RStudio Job Launcher type: application -version: 0.2.20 -appVersion: 0.2.20 +version: 0.2.24 +appVersion: 0.2.21 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png sources: - https://github.com/rstudio/helm @@ -13,8 +13,8 @@ maintainers: url: https://github.com/sol-eng dependencies: - name: rstudio-library - version: 0.1.29 - repository: file://../rstudio-library + version: 0.1.31 + repository: https://helm.rstudio.com keywords: - "data science" - "machine learning" diff --git a/charts/rstudio-launcher-rbac/NEWS.md b/charts/rstudio-launcher-rbac/NEWS.md index 03e29eb4..2177a3fe 100644 --- a/charts/rstudio-launcher-rbac/NEWS.md +++ b/charts/rstudio-launcher-rbac/NEWS.md @@ -1,5 +1,21 @@ # Changelog +## 0.2.24 + +- Pin the rstudio-library version dependency so we can update the library chart without breaking all the charts that depend on it. + +## 0.2.23 + +- Add helm unit test scaffold. + +## 0.2.22 + +- Move the values files for linting and installation testing outside the chart directory so that we can iterate on them without releasing a new version of the chart + +## 0.2.21 + +- Documentation site updates + ## 0.2.20 - Updates to support standalone documentation site diff --git a/charts/rstudio-launcher-rbac/README.md b/charts/rstudio-launcher-rbac/README.md index 313d989f..1dd1a38f 100644 --- a/charts/rstudio-launcher-rbac/README.md +++ b/charts/rstudio-launcher-rbac/README.md @@ -1,32 +1,36 @@ # rstudio-launcher-rbac -![Version: 0.2.20](https://img.shields.io/badge/Version-0.2.20-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.2.20](https://img.shields.io/badge/AppVersion-0.2.20-informational?style=flat-square) +![Version: 0.2.24](https://img.shields.io/badge/Version-0.2.24-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.2.21](https://img.shields.io/badge/AppVersion-0.2.21-informational?style=flat-square) #### _RBAC definition for the RStudio Job Launcher_ -## For Production +## For production -To ensure a stable production deployment, please: +To ensure a stable production deployment: -* Ensure you "pin" the version of the Helm chart that you are using. You can do - this using the `helm dependency` command and the associated "Chart.lock" files - or the `--version` flag. **IMPORTANT: This protects you from breaking changes** -* Before upgrading, to avoid breaking changes, use `helm diff upgrade` to check - for breaking changes -* Pay close attention to [`NEWS.md`](./NEWS.md) for updates on breaking - changes, as well as documentation below on how to use the chart +* "Pin" the version of the Helm chart that you are using. You can do this using the: + * `helm dependency` command *and* the associated "Chart.lock" files *or* + * the `--version` flag. + + ::: {.callout-important} + This protects you from breaking changes. + ::: -## Installing the Chart +* Before upgrading check for breaking changes using `helm-diff` plugin and `helm diff upgrade`. +* Read [`NEWS.md`](./NEWS.md) for updates on breaking changes and the documentation below on how to use the chart. -To install the chart with the release name `my-release` at version 0.2.20: +## Installing the chart -```bash +To install the chart with the release name `my-release` at version 0.2.24: + +```{.bash} helm repo add rstudio https://helm.rstudio.com -helm upgrade --install my-release rstudio/rstudio-launcher-rbac --version=0.2.20 +helm upgrade --install my-release rstudio/rstudio-launcher-rbac --version=0.2.24 ``` -To explore other chart versions, take a look at: -``` +To explore other chart versions, look at: + +```{.bash} helm search repo rstudio/rstudio-launcher-rbac -l ``` @@ -58,5 +62,5 @@ helm template -n rstudio rstudio-launcher-rbac rstudio/rstudio-launcher-rbac | targetNamespaces | list | `[]` | The targetNamespaces that the launcher will be able to launch sessions into | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0) +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/charts/rstudio-library/.helmignore b/charts/rstudio-library/.helmignore index 0e8a0eb3..f70705f1 100644 --- a/charts/rstudio-library/.helmignore +++ b/charts/rstudio-library/.helmignore @@ -21,3 +21,6 @@ .idea/ *.tmproj .vscode/ + +# chart tests +tests/ diff --git a/charts/rstudio-library/Chart.yaml b/charts/rstudio-library/Chart.yaml index 3ca284ce..c497be93 100644 --- a/charts/rstudio-library/Chart.yaml +++ b/charts/rstudio-library/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: rstudio-library description: Helm library helpers for use by official RStudio charts type: library -version: 0.1.29 -appVersion: 0.1.29 +version: 0.1.31 +appVersion: 0.1.31 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png home: https://www.rstudio.com diff --git a/charts/rstudio-library/NEWS.md b/charts/rstudio-library/NEWS.md index 9ac54457..109c8828 100644 --- a/charts/rstudio-library/NEWS.md +++ b/charts/rstudio-library/NEWS.md @@ -1,5 +1,13 @@ # Changelog +## 0.1.31 + +- Add helm unit test scaffold. + +## 0.1.30 + +- Documentation site updates + ## 0.1.29 - Updates to support standalone documentation site diff --git a/charts/rstudio-library/README.md b/charts/rstudio-library/README.md index 86e0ab9d..eea6e619 100644 --- a/charts/rstudio-library/README.md +++ b/charts/rstudio-library/README.md @@ -1,20 +1,23 @@ # rstudio-library -![Version: 0.1.29](https://img.shields.io/badge/Version-0.1.29-informational?style=flat-square) ![Type: library](https://img.shields.io/badge/Type-library-informational?style=flat-square) ![AppVersion: 0.1.29](https://img.shields.io/badge/AppVersion-0.1.29-informational?style=flat-square) +![Version: 0.1.31](https://img.shields.io/badge/Version-0.1.31-informational?style=flat-square) ![Type: library](https://img.shields.io/badge/Type-library-informational?style=flat-square) ![AppVersion: 0.1.31](https://img.shields.io/badge/AppVersion-0.1.31-informational?style=flat-square) #### _Helm library helpers for use by official RStudio charts_ -## For Production +## For production -To ensure a stable production deployment, please: +To ensure a stable production deployment: -* Ensure you "pin" the version of the Helm chart that you are using. You can do - this using the `helm dependency` command and the associated "Chart.lock" files - or the `--version` flag. **IMPORTANT: This protects you from breaking changes** -* Before upgrading, to avoid breaking changes, use `helm diff upgrade` to check - for breaking changes -* Pay close attention to [`NEWS.md`](./NEWS.md) for updates on breaking - changes, as well as documentation below on how to use the chart +* "Pin" the version of the Helm chart that you are using. You can do this using the: + * `helm dependency` command *and* the associated "Chart.lock" files *or* + * the `--version` flag. + + ::: {.callout-important} + This protects you from breaking changes. + ::: + +* Before upgrading check for breaking changes using `helm-diff` plugin and `helm diff upgrade`. +* Read [`NEWS.md`](./NEWS.md) for updates on breaking changes and the documentation below on how to use the chart. # Usage @@ -31,5 +34,5 @@ If you are curious about its usage, take a look at the other charts (i.e. `rstud for `rstudio-library` in the `templates/` directory. ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0) +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/charts/rstudio-pm/.helmignore b/charts/rstudio-pm/.helmignore new file mode 100644 index 00000000..f70705f1 --- /dev/null +++ b/charts/rstudio-pm/.helmignore @@ -0,0 +1,26 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ + +# chart tests +tests/ diff --git a/charts/rstudio-pm/Chart.lock b/charts/rstudio-pm/Chart.lock index 56bdeeeb..49dfebde 100644 --- a/charts/rstudio-pm/Chart.lock +++ b/charts/rstudio-pm/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: rstudio-library - repository: file://../rstudio-library - version: 0.1.29 -digest: sha256:ccca30d883d295668402d63328b1d603911ef717b41207f9b3a2e4d1dd3af1a3 -generated: "2024-04-01T12:17:57.728915-04:00" + repository: https://helm.rstudio.com + version: 0.1.31 +digest: sha256:2a0e98b8fa01730bf2db3816a7310462c921b9fa2f1f3c74f85fedede82e1593 +generated: "2024-11-01T10:21:00.666975-04:00" diff --git a/charts/rstudio-pm/Chart.yaml b/charts/rstudio-pm/Chart.yaml index 76a4357d..1cf27820 100644 --- a/charts/rstudio-pm/Chart.yaml +++ b/charts/rstudio-pm/Chart.yaml @@ -1,8 +1,8 @@ name: rstudio-pm -description: Official Helm chart for RStudio Package Manager -version: 0.5.25 +description: Official Helm chart for Posit Package Manager +version: 0.5.43 apiVersion: v2 -appVersion: 2024.04.0 +appVersion: 2024.11.0 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png home: https://www.rstudio.com sources: @@ -14,12 +14,12 @@ maintainers: url: https://github.com/rstudio/helm dependencies: - name: rstudio-library - version: 0.1.29 - repository: file://../rstudio-library + version: 0.1.31 + repository: https://helm.rstudio.com annotations: artifacthub.io/images: | - name: rstudio-package-manager - image: rstudio/rstudio-package-manager:ubuntu2204-2024.04.0 + image: rstudio/rstudio-package-manager:ubuntu2204-2024.11.0 artifacthub.io/license: MIT artifacthub.io/links: | - name: RStudio Community diff --git a/charts/rstudio-pm/NEWS.md b/charts/rstudio-pm/NEWS.md index 491bdc2b..baf898b8 100644 --- a/charts/rstudio-pm/NEWS.md +++ b/charts/rstudio-pm/NEWS.md @@ -1,5 +1,76 @@ # Changelog +## 0.5.43 + +- Update default Posit Package Manager version to 2024.11.0-7 + +## 0.5.41 + +- Update the default `pod.startupProbe` to use the `/__api__/status` route instead of `/__ping__` for a more reliable startup. + +## 0.5.40 + +- Add helm unit test scaffold. + +## 0.5.39 + +- Add the `fsGroupChangePolicy: "OnRootMismatch"` default option to the pod's `securityContext`. This will only ensure + permissions and ownership change only if the permission and the ownership of root directory does not match with + expected permissions of the volume. + +## 0.5.38 + +- Move the values files for linting and installation testing outside the chart directory so that we can iterate on them without releasing a new version of the chart + +## 0.5.37 + +- Update documentation with lowercase `Database.Provider = "postgres"`. + +## 0.5.36 + +- Update the PostgreSQL configuration documentation to temporarily work around bug with `Postgres.UsageDataPassword` in Package Manager 2024.08.2. + +## 0.5.35 + +- Move `pod.containerSecurityContext.fsGroup = 999` to `pod.securityContext.fsGroup` to resolve + the helm warning `unknown field "spec.template.spec.containers[0].securityContext.fsGroup"`. + +## 0.5.34 + +- Add `pod.containerSecurityContext.fsGroup = 999` value to set file permissions correctly when using shared storage. + +## 0.5.33 + +- Update default Post Package Manager version to 2024.08.2-9 + +## 0.5.32 + +- Bump Chronicle Agent to version 2024.09.0 + +## 0.5.31 + +- Add documentation about PostgreSQL database configuration and mounting passwords from secrets as an env variable + +## 0.5.30 + +- Update default Posit Package Manager version to 2024.08.0-6 + +## 0.5.29 + +- Update default Posit Package Manager version to 2024.04.4-35 + +## 0.5.28 + +- Update default Posit Package Manager version to 2024.04.2-29 + +## 0.5.27 + +- Update `strategy` section of `deployment.yaml` template to be consistent with other Posit products. `RollingUpdate` is still the default strategy. + +## 0.5.26 + +- Documentation site updates + ## 0.5.25 - Update default Posit Package Manager version to 2024.04.0-20 diff --git a/charts/rstudio-pm/README.md b/charts/rstudio-pm/README.md index b6f9d265..906061de 100644 --- a/charts/rstudio-pm/README.md +++ b/charts/rstudio-pm/README.md @@ -1,71 +1,76 @@ # Posit Package Manager -![Version: 0.5.25](https://img.shields.io/badge/Version-0.5.25-informational?style=flat-square) ![AppVersion: 2024.04.0](https://img.shields.io/badge/AppVersion-2024.04.0-informational?style=flat-square) +![Version: 0.5.43](https://img.shields.io/badge/Version-0.5.43-informational?style=flat-square) ![AppVersion: 2024.11.0](https://img.shields.io/badge/AppVersion-2024.11.0-informational?style=flat-square) -#### _Official Helm chart for RStudio Package Manager_ +#### _Official Helm chart for Posit Package Manager_ IT Administrators use [Posit Package Manager](https://posit.co/products/enterprise/package-manager/) to control and manage R and Python packages that Data Scientists need to create and share data products. -## For Production +## For production -To ensure a stable production deployment, please: +To ensure a stable production deployment: -* Ensure you "pin" the version of the Helm chart that you are using. You can do - this using the `helm dependency` command and the associated "Chart.lock" files - or the `--version` flag. **IMPORTANT: This protects you from breaking changes** -* Before upgrading, to avoid breaking changes, use `helm diff upgrade` to check - for breaking changes -* Pay close attention to [`NEWS.md`](./NEWS.md) for updates on breaking - changes, as well as documentation below on how to use the chart +* "Pin" the version of the Helm chart that you are using. You can do this using the: + * `helm dependency` command *and* the associated "Chart.lock" files *or* + * the `--version` flag. + + ::: {.callout-important} + This protects you from breaking changes. + ::: -## Installing the Chart +* Before upgrading check for breaking changes using `helm-diff` plugin and `helm diff upgrade`. +* Read [`NEWS.md`](./NEWS.md) for updates on breaking changes and the documentation below on how to use the chart. -To install the chart with the release name `my-release` at version 0.5.25: +## Installing the chart -```bash +To install the chart with the release name `my-release` at version 0.5.43: + +```{.bash} helm repo add rstudio https://helm.rstudio.com -helm upgrade --install my-release rstudio/rstudio-pm --version=0.5.25 +helm upgrade --install my-release rstudio/rstudio-pm --version=0.5.43 ``` -To explore other chart versions, take a look at: -``` +To explore other chart versions, look at: + +```{.bash} helm search repo rstudio/rstudio-pm -l ``` -## Upgrade Guidance +## Upgrade guidance ### 0.4.0 - When upgrading to version 0.4.0 or later, the Package Manager service moves from running as `root` to running as - the `rstudio-pm` user (with `uid:gid` `999:999`). A `chown` of persistent storage may be required. We will try to - fix this up automatically. Set `enableMigrations=false` to disable the automatic fixup / hook. + the `rstudio-pm` user (with `uid:gid` `999:999`). +- A `chown` of persistent storage may be required. The team is working to implement an automatic fix. To disable the automatic fix/hook, set `enableMigrations=false`. -## Required Configuration +## Required configuration This chart requires the following in order to function: -* A license file, license key, or address of a running license server. See the [Licensing](#licensing) section below for more details. -* A Kubernetes [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) that contains the data directory for RSPM. - * If `sharedStorage.create` is set, a PVC that relies on the default storage class will be created to generate the PersistentVolume. +* A license file. See the [Licensing](#licensing) section below for more details. +* A Kubernetes [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) that contains the data directory for Package Manager. + * If `sharedStorage.create` is set, it creates a Persistent Volume Claim (PVC) that relies on the default storage class to generate the + PersistentVolume. Most Kubernetes environments do not have a default storage class that you can use with `ReadWriteMany` access mode out-of-the-box. In this case, we recommend you disable `sharedStorage.create` and create your own `PersistentVolume` and `PersistentVolumeClaim`, then mount them into the container by specifying the `pod.volumes` and `pod.volumeMounts` parameters, or by specifying your `PersistentVolumeClaim` using `sharedStorage.name` and `sharedStorage.mount`. - * If you cannot use a `PersistentVolume` to properly mount your data directory, you'll need to mount your data in the container + * If you cannot use a `PersistentVolume` to properly mount your data directory, mount your data in the container by using a regular [Kubernetes Volume](https://kubernetes.io/docs/concepts/storage/volumes), specified in `pod.volumes` and `pod.volumeMounts`. * Alternatively, S3 storage can be used. See the [S3 Configuration](#s3-configuration) section for details. ## Licensing -This chart supports activating the product using a license file, license key, or license server. In the case of a license file or key, we recommend against placing it in your values file directly. - -### License File +This chart supports activating the product using a *license file*. We recommend storing a license file as a `Secret` and setting the `license.file.secret` and `license.file.secretKey` values accordingly. First, create the secret declaratively with YAML or imperatively using the following command: -`kubectl create secret generic rstudio-pm-license --from-file=licenses/rstudio-pm.lic` +```{.bash} +kubectl create secret generic rstudio-pm-license --from-file=licenses/rstudio-pm.lic +``` Second, specify the following values: @@ -78,20 +83,62 @@ license: Alternatively, license files can be set during `helm install` with the following argument: -`--set-file license.file.contents=licenses/rstudio-pm.lic` +```{.bash} +--set-file license.file.contents=licenses/rstudio-pm.lic +``` + +## Database + +Package Manager requires a PostgreSQL database when running in Kubernetes. You must configure a [valid connection URI and a password](https://docs.posit.co/rspm/admin/database/#database-postgres) for the product to function correctly. Both the connection URI and password may be specified in the `config` section of `values.yaml`. However, we recommend only adding the connection URI and putting the database password in a Kubernetes `Secret`, which can be [automatically set as an environment variable](#database-password). -### License Key +### Database configuration -Set a license key directly in your values file (`license.key`) or during `helm install` with the argument `--set license.key=XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX`. +Add the following to your `values.yaml`, replacing the `URL` with your database details. -### License Server +```yaml +config: + Database: + Provider: "postgres" + Postgres: + URL: "postgres://@:/" +``` -Set a license server directly in your values file (`license.server`) or during `helm install` with the argument `--set license.server=`. +### Database password -## S3 Configuration +First, create a `Secret` declaratively with YAML or imperatively using the following command (replacing with your actual password): + +```bash +kubectl create secret generic rstudio-pm-database --from-literal=password=YOURPASSWORDHERE +``` + +Second, specify the following in your `values.yaml`: + +```yaml +pod: + env: + - name: PACKAGEMANAGER_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: rstudio-pm-database + key: password + + # Temporarily work around bug in Package Manager 2024.08.2 where Postgres.UsageDataPassword + # does not default to Postgres.Password. This will be fixed in the next release of Package Manager. + - name: PACKAGEMANAGER_POSTGRES_USAGEDATAPASSWORD + valueFrom: + secretKeyRef: + name: rstudio-pm-database + key: password +``` + +Alternatively, database passwords may be set during `helm install` with the following argument: + +`--set config.Postgres.Password=""` + +## S3 configuration Package Manager [can be configured to store its data in S3 -buckets](https://docs.rstudio.com/rspm/admin/files-directories/#data-destinations), +buckets](https://docs.posit.co/rspm/admin/file-storage/file-storage/#data-destinations), which eliminates the need to provision shared storage for multiple replicas. A `values.yaml` file using S3 might contain something like the following: @@ -129,17 +176,17 @@ awsSecretAccessKey: your-secret-access-key Bear in mind that static, long-lived credentials are the least secure option and should be avoided if at all possible. -## General Principles +## General principles -- In most places, we opt to pass helm values over configmaps. We translate these into the valid `.gcfg` file format +- In most places, we opt to pass Helm values over configmaps. We translate these into the valid `.gcfg` file format required by rstudio-pm. -## Configuration File +## Configuration file -The configuration values all take the form of usual helm values +The configuration values all take the form of usual Helm values so you can set the database password with something like: -``` +```{.bash} ... --set config.Postgres.Password=mypassword ... ``` @@ -174,7 +221,7 @@ The Helm `config` values are converted into the `rstudio-pm.gcfg` service config | license.file | object | `{"contents":false,"mountPath":"/etc/rstudio-licensing","mountSubPath":false,"secret":false,"secretKey":"license.lic"}` | the file section is used for licensing with a license file | | license.file.contents | bool | `false` | contents is an in-line license file | | license.file.mountPath | string | `"/etc/rstudio-licensing"` | mountPath is the place the license file will be mounted into the container | -| license.file.mountSubPath | bool | `false` | mountSubPath is whether to mount the subPath for the file secret. -- It can be preferable _not_ to enable this, because then updates propagate automatically | +| license.file.mountSubPath | bool | `false` | It can be preferable _not_ to enable this, because then updates propagate automatically | | license.file.secret | bool | `false` | secret is an existing secret with a license file in it | | license.file.secretKey | string | `"license.lic"` | secretKey is the key for the secret to use for the license file | | license.key | string | `nil` | key is the license to use | @@ -187,7 +234,7 @@ The Helm `config` values are converted into the `rstudio-pm.gcfg` service config | pod.env | list | `[]` | env is an array of maps that is injected as-is into the "env:" component of the pod.container spec | | pod.labels | object | `{}` | Additional labels to add to the rstudio-pm pods | | pod.lifecycle | object | `{}` | Container [lifecycle hooks](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/) | -| pod.securityContext | object | `{}` | the [securityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the pod | +| pod.securityContext | object | `{"fsGroup":999,"fsGroupChangePolicy":"OnRootMismatch"}` | the [securityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the pod | | pod.serviceAccountName | string | `""` | Deprecated, use `serviceAccount.name` instead | | pod.terminationGracePeriodSeconds | int | `120` | The termination grace period seconds allowed for the pod before shutdown | | pod.volumeMounts | list | `[]` | volumeMounts is an array of maps that is injected as-is into the "volumeMounts" component of the pod spec | @@ -207,7 +254,7 @@ The Helm `config` values are converted into the `rstudio-pm.gcfg` service config | service.type | string | `"ClusterIP"` | The service type, usually ClusterIP (in-cluster only) or LoadBalancer (to expose the service using your cloud provider's load balancer) | | serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount, if any | | serviceAccount.create | bool | `true` | Whether to create a [Service Account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) | -| serviceAccount.labels | object | `{}` | | +| serviceAccount.labels | object | `{}` | Labels for the ServiceAccount, if any | | serviceAccount.name | string | When `serviceAccount.create` is `true` this defaults to the full name of the release | ServiceAccount to use, if any, or an explicit name for the one we create | | serviceMonitor.additionalLabels | object | `{}` | additionalLabels normally includes the release name of the Prometheus Operator | | serviceMonitor.enabled | bool | `false` | Whether to create a ServiceMonitor CRD for use with a Prometheus Operator | @@ -222,7 +269,7 @@ The Helm `config` values are converted into the `rstudio-pm.gcfg` service config | sharedStorage.selector | object | `{}` | selector for PVC definition | | sharedStorage.storageClassName | bool | `false` | storageClassName - the type of storage to use. Must allow ReadWriteMany | | sharedStorage.volumeName | string | `""` | the volumeName passed along to the persistentVolumeClaim. Optional | -| startupProbe | object | `{"enabled":false,"failureThreshold":30,"httpGet":{"path":"/__ping__","port":4242},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":1}` | startupProbe is used to configure the container's startupProbe | +| startupProbe | object | `{"enabled":false,"failureThreshold":30,"httpGet":{"path":"/__api__/status","port":4242},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":1}` | startupProbe is used to configure the container's startupProbe | | startupProbe.failureThreshold | int | `30` | failureThreshold * periodSeconds should be strictly > worst case startup time | | strategy | object | `{"rollingUpdate":{"maxSurge":"100%","maxUnavailable":0},"type":"RollingUpdate"}` | The update strategy used by the main service pod. | | tolerations | list | `[]` | An array used verbatim as the pod's "tolerations" definition | @@ -230,5 +277,5 @@ The Helm `config` values are converted into the `rstudio-pm.gcfg` service config | versionOverride | string | `""` | A Package Manager version to override the "tag" for the RStudio Package Manager image. Necessary until https://github.com/helm/helm/issues/8194 | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0) +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/charts/rstudio-pm/README.md.gotmpl b/charts/rstudio-pm/README.md.gotmpl index d0d4cc81..4a77167e 100644 --- a/charts/rstudio-pm/README.md.gotmpl +++ b/charts/rstudio-pm/README.md.gotmpl @@ -8,34 +8,83 @@ {{ template "rstudio.install" . }} -## Upgrade Guidance +## Upgrade guidance ### 0.4.0 - When upgrading to version 0.4.0 or later, the Package Manager service moves from running as `root` to running as - the `rstudio-pm` user (with `uid:gid` `999:999`). A `chown` of persistent storage may be required. We will try to - fix this up automatically. Set `enableMigrations=false` to disable the automatic fixup / hook. + the `rstudio-pm` user (with `uid:gid` `999:999`). +- A `chown` of persistent storage may be required. The team is working to implement an automatic fix. To disable the automatic fix/hook, set `enableMigrations=false`. -## Required Configuration +## Required configuration This chart requires the following in order to function: -* A license file, license key, or address of a running license server. See the [Licensing](#licensing) section below for more details. -* A Kubernetes [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) that contains the data directory for RSPM. - * If `sharedStorage.create` is set, a PVC that relies on the default storage class will be created to generate the PersistentVolume. +* A license file. See the [Licensing](#licensing) section below for more details. +* A Kubernetes [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) that contains the data directory for Package Manager. + * If `sharedStorage.create` is set, it creates a Persistent Volume Claim (PVC) that relies on the default storage class to generate the + PersistentVolume. Most Kubernetes environments do not have a default storage class that you can use with `ReadWriteMany` access mode out-of-the-box. In this case, we recommend you disable `sharedStorage.create` and create your own `PersistentVolume` and `PersistentVolumeClaim`, then mount them into the container by specifying the `pod.volumes` and `pod.volumeMounts` parameters, or by specifying your `PersistentVolumeClaim` using `sharedStorage.name` and `sharedStorage.mount`. - * If you cannot use a `PersistentVolume` to properly mount your data directory, you'll need to mount your data in the container + * If you cannot use a `PersistentVolume` to properly mount your data directory, mount your data in the container by using a regular [Kubernetes Volume](https://kubernetes.io/docs/concepts/storage/volumes), specified in `pod.volumes` and `pod.volumeMounts`. * Alternatively, S3 storage can be used. See the [S3 Configuration](#s3-configuration) section for details. {{ template "rstudio.licensing" . }} -## S3 Configuration +## Database + +Package Manager requires a PostgreSQL database when running in Kubernetes. You must configure a [valid connection URI and a password](https://docs.posit.co/rspm/admin/database/#database-postgres) for the product to function correctly. Both the connection URI and password may be specified in the `config` section of `values.yaml`. However, we recommend only adding the connection URI and putting the database password in a Kubernetes `Secret`, which can be [automatically set as an environment variable](#database-password). + +### Database configuration + +Add the following to your `values.yaml`, replacing the `URL` with your database details. + +```yaml +config: + Database: + Provider: "postgres" + Postgres: + URL: "postgres://@:/" +``` + +### Database password + +First, create a `Secret` declaratively with YAML or imperatively using the following command (replacing with your actual password): + +```bash +kubectl create secret generic {{ .Name }}-database --from-literal=password=YOURPASSWORDHERE +``` + +Second, specify the following in your `values.yaml`: + +```yaml +pod: + env: + - name: PACKAGEMANAGER_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Name }}-database + key: password + + # Temporarily work around bug in Package Manager 2024.08.2 where Postgres.UsageDataPassword + # does not default to Postgres.Password. This will be fixed in the next release of Package Manager. + - name: PACKAGEMANAGER_POSTGRES_USAGEDATAPASSWORD + valueFrom: + secretKeyRef: + name: {{ .Name }}-database + key: password +``` + +Alternatively, database passwords may be set during `helm install` with the following argument: + +`--set config.Postgres.Password=""` + +## S3 configuration Package Manager [can be configured to store its data in S3 -buckets](https://docs.rstudio.com/rspm/admin/files-directories/#data-destinations), +buckets](https://docs.posit.co/rspm/admin/file-storage/file-storage/#data-destinations), which eliminates the need to provision shared storage for multiple replicas. A `values.yaml` file using S3 might contain something like the following: @@ -73,17 +122,17 @@ awsSecretAccessKey: your-secret-access-key Bear in mind that static, long-lived credentials are the least secure option and should be avoided if at all possible. -## General Principles +## General principles -- In most places, we opt to pass helm values over configmaps. We translate these into the valid `.gcfg` file format +- In most places, we opt to pass Helm values over configmaps. We translate these into the valid `.gcfg` file format required by {{ template "chart.name" . }}. -## Configuration File +## Configuration file -The configuration values all take the form of usual helm values +The configuration values all take the form of usual Helm values so you can set the database password with something like: -``` +```{.bash} ... --set config.Postgres.Password=mypassword ... ``` diff --git a/charts/rstudio-pm/templates/deployment.yaml b/charts/rstudio-pm/templates/deployment.yaml index f7fff44c..5f4cb479 100644 --- a/charts/rstudio-pm/templates/deployment.yaml +++ b/charts/rstudio-pm/templates/deployment.yaml @@ -5,10 +5,13 @@ metadata: name: {{ include "rstudio-pm.fullname" . }} namespace: {{ $.Release.Namespace }} spec: - {{- with .Values.strategy }} strategy: - {{- toYaml . | nindent 4 }} - {{- end }} + type: {{ .Values.strategy.type }} + {{- if eq .Values.strategy.type "RollingUpdate" }} + rollingUpdate: + maxUnavailable: {{ .Values.strategy.rollingUpdate.maxUnavailable }} + maxSurge: {{ .Values.strategy.rollingUpdate.maxSurge }} + {{- end }} replicas: {{ .Values.replicas }} selector: matchLabels: diff --git a/charts/rstudio-pm/values.yaml b/charts/rstudio-pm/values.yaml index a5ce17fb..b5295edb 100644 --- a/charts/rstudio-pm/values.yaml +++ b/charts/rstudio-pm/values.yaml @@ -125,7 +125,9 @@ pod: # -- Container [lifecycle hooks](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/) lifecycle: {} # -- the [securityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the pod - securityContext: {} + securityContext: + fsGroup: 999 + fsGroupChangePolicy: "OnRootMismatch" # -- the [securityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the main Package Manager container. Evaluated as a template. containerSecurityContext: runAsUser: 999 @@ -168,7 +170,7 @@ livenessProbe: startupProbe: enabled: false httpGet: - path: /__ping__ + path: /__api__/status port: 4242 initialDelaySeconds: 10 periodSeconds: 10 diff --git a/charts/rstudio-workbench/.helmignore b/charts/rstudio-workbench/.helmignore index ed4080b1..1cbd52de 100644 --- a/charts/rstudio-workbench/.helmignore +++ b/charts/rstudio-workbench/.helmignore @@ -1,3 +1,6 @@ snapshot/ Makefile *.gotmpl + +# chart tests +tests/ diff --git a/charts/rstudio-workbench/Chart.lock b/charts/rstudio-workbench/Chart.lock index 0c73882b..5d8d4207 100644 --- a/charts/rstudio-workbench/Chart.lock +++ b/charts/rstudio-workbench/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: rstudio-library - repository: file://../rstudio-library - version: 0.1.29 -digest: sha256:ccca30d883d295668402d63328b1d603911ef717b41207f9b3a2e4d1dd3af1a3 -generated: "2024-04-01T12:18:00.109138-04:00" + repository: https://helm.rstudio.com + version: 0.1.31 +digest: sha256:2a0e98b8fa01730bf2db3816a7310462c921b9fa2f1f3c74f85fedede82e1593 +generated: "2024-11-01T10:20:55.670732-04:00" diff --git a/charts/rstudio-workbench/Chart.yaml b/charts/rstudio-workbench/Chart.yaml index b44fb106..734f2098 100644 --- a/charts/rstudio-workbench/Chart.yaml +++ b/charts/rstudio-workbench/Chart.yaml @@ -1,8 +1,8 @@ name: rstudio-workbench -description: Official Helm chart for RStudio Workbench -version: 0.7.3 +description: Official Helm chart for Posit Workbench +version: 0.8.10 apiVersion: v2 -appVersion: 2024.04.0 +appVersion: 2024.12.0 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png home: https://www.rstudio.com sources: @@ -13,14 +13,14 @@ maintainers: url: https://github.com/sol-eng dependencies: - name: rstudio-library - version: 0.1.29 - repository: file://../rstudio-library + version: 0.1.31 + repository: https://helm.rstudio.com annotations: artifacthub.io/images: | - name: rstudio-workbench - image: rstudio/rstudio-workbench:ubuntu2204-2024.04.0 + image: rstudio/rstudio-workbench:ubuntu2204-2024.12.0 - name: r-session-complete - image: rstudio/r-session-complete:ubuntu2204-2024.04.0 + image: rstudio/r-session-complete:ubuntu2204-2024.12.0 artifacthub.io/license: MIT artifacthub.io/links: | - name: Docker Images diff --git a/charts/rstudio-workbench/NEWS.md b/charts/rstudio-workbench/NEWS.md index 1f0e7e46..c0fce2eb 100644 --- a/charts/rstudio-workbench/NEWS.md +++ b/charts/rstudio-workbench/NEWS.md @@ -1,5 +1,71 @@ # Changelog +## 0.8.10 + +- Bump Workbench version to 2024.12.0 +- Bump version of launcher templates `job.tpl` and `service.tpl` + - Populate pod `initContainers` from `.Job.initContainers` + +## 0.8.9 + +- Fix a logic bug where the resource limit key was set even if `resources.limits.enabled` is false + +## 0.8.8 + +- Bump Chronicle Agent to version 2024.11.0 + +## 0.8.7 + +- Bump Workbench version to 2024.09.1 + +## 0.8.6 + +- Pin the rstudio-library version dependency so we can update the library chart without breaking all the charts that depend on it. + +## 0.8.5 + +- Add helm unit test scaffold. + +## 0.8.4 + +- Move the values files for linting and installation testing outside the chart directory so that we can iterate on them without releasing a new version of the chart + +## 0.8.3 + +- Bump version of launcher templates `job.tpl` and `service.tpl` + - `enableServiceLinks` now defaults to `false` for sessions (instead of not being set). + To enable them for sessions, set `launcher.templateValues.enableServiceLinks: true` + - Also see related discussion [on the Kubernetes project](https://github.com/kubernetes/kubernetes/issues/121787) + +## 0.8.2 + +- Bump Workbench version to 2024.09.0 + +## 0.8.1 + +- Bump Chronicle Agent to version 2024.09.0 + +## 0.8.0 + +- BREAKING: the prometheus endpoint has changed from port `9108` to `8989` by default + - We are now using an internal prometheus endpoint with new metrics + - As a result, the `graphiteExporter` sidecar has been removed + - Some metrics from the `graphiteExporter` will no longer be present + - The parent / main "off-switch" for prometheus is at `prometheus.enabled` + - To revert to the old exporter, set `prometheus.legacy=true` (and please reach out to let us know why!) + +## 0.7.6 + +- Bump Workbench version to 2024.04.2 + +## 0.7.5 + +- Add documentation about PostgreSQL database configuration and mounting passwords from secrets as env variables + +## 0.7.4 + +- Documentation site updates + ## 0.7.3 - Bump Workbench version to 2024.04.0 diff --git a/charts/rstudio-workbench/README.md b/charts/rstudio-workbench/README.md index 9cda63d7..2b5700ea 100644 --- a/charts/rstudio-workbench/README.md +++ b/charts/rstudio-workbench/README.md @@ -1,87 +1,94 @@ # Posit Workbench -![Version: 0.7.3](https://img.shields.io/badge/Version-0.7.3-informational?style=flat-square) ![AppVersion: 2024.04.0](https://img.shields.io/badge/AppVersion-2024.04.0-informational?style=flat-square) +![Version: 0.8.10](https://img.shields.io/badge/Version-0.8.10-informational?style=flat-square) ![AppVersion: 2024.12.0](https://img.shields.io/badge/AppVersion-2024.12.0-informational?style=flat-square) -#### _Official Helm chart for RStudio Workbench_ +#### _Official Helm chart for Posit Workbench_ Data Scientists use [Posit Workbench](https://posit.co/products/enterprise/workbench/) to analyze data and create data products using R and Python. -## For Production +## For production -To ensure a stable production deployment, please: +To ensure a stable production deployment: -* Ensure you "pin" the version of the Helm chart that you are using. You can do - this using the `helm dependency` command and the associated "Chart.lock" files - or the `--version` flag. **IMPORTANT: This protects you from breaking changes** -* Before upgrading, to avoid breaking changes, use `helm diff upgrade` to check - for breaking changes -* Pay close attention to [`NEWS.md`](./NEWS.md) for updates on breaking - changes, as well as documentation below on how to use the chart +* "Pin" the version of the Helm chart that you are using. You can do this using the: + * `helm dependency` command *and* the associated "Chart.lock" files *or* + * the `--version` flag. + + ::: {.callout-important} + This protects you from breaking changes. + ::: -## Installing the Chart +* Before upgrading check for breaking changes using `helm-diff` plugin and `helm diff upgrade`. +* Read [`NEWS.md`](./NEWS.md) for updates on breaking changes and the documentation below on how to use the chart. -To install the chart with the release name `my-release` at version 0.7.3: +## Installing the chart -```bash +To install the chart with the release name `my-release` at version 0.8.10: + +```{.bash} helm repo add rstudio https://helm.rstudio.com -helm upgrade --install my-release rstudio/rstudio-workbench --version=0.7.3 +helm upgrade --install my-release rstudio/rstudio-workbench --version=0.8.10 ``` -To explore other chart versions, take a look at: -``` +To explore other chart versions, look at: + +```{.bash} helm search repo rstudio/rstudio-workbench -l ``` -## Required Configuration +## Required configuration -This chart requires the following in order to function: +To function, this chart requires the following: -* A license file, license key, or address of a running license server. See the [Licensing](#licensing) section below for more details. +* A license file. See the [Licensing](#licensing) section below for more details. * A Kubernetes [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) that contains the home directory for users. - * If `homeStorage.create` is set, a PVC that relies on the default storage class will be created to generate the + * If `homeStorage.create` is set, it creates a Persistent Volume Claim (PVC) that relies on the default storage class to generate the PersistentVolume. Most Kubernetes environments do not have a default storage class that you can use - with `ReadWriteMany` access mode out-of-the-box. In this case, we recommend you disable `homeStorage.create` and - create your own `PersistentVolume` and `PersistentVolumeClaim`, then mount them into the container by specifying + with `ReadWriteMany` access mode out-of-the-box. In this case, we recommend that you: + * Disable `homeStorage.create` and + create your own `PersistentVolume` and `PersistentVolumeClaim`, then + * Mount them into the container by specifying the `pod.volumes` and `pod.volumeMounts` parameters, or by specifying your `PersistentVolumeClaim` using `homeStorage.name` and `homeStorage.mount`. - * If you cannot use a `PersistentVolume` to properly mount your users' home directories, you'll need to mount your + * If you cannot use a `PersistentVolume` to properly mount your users' home directories, mount your data in the container by using a regular [Kubernetes Volume](https://kubernetes.io/docs/concepts/storage/volumes/#nfs), specified in `pod.volumes` and `pod.volumeMounts`. - * If you cannot use a `Volume` to mount the directories, you'll need to manually mount them during container startup + * If you cannot use a `Volume` to mount the directories, manually mount them during container startup with a mechanism similar to what is described below for joining to auth domains. - * If not using `homeStorage.create`, you'll need to configure `config.serverDcf.launcher-mounts` to ensure that the correct mounts are used when users create new sessions. -* If using load balancing (by setting `replicas > 1`), you will need similar storage defined for `sharedStorage` to + * If not using `homeStorage.create`, configure `config.serverDcf.launcher-mounts` to ensure that the correct mounts are used when users create new sessions. +* If using load balancing (by setting `replicas > 1`), you need similar storage defined for `sharedStorage` to store shared project configuration. However, you can also configure the product to store its shared data underneath `/home` by setting `config.server.rserver\.conf.server-shared-storage-path=/home/some-shared-dir`. * A method to join the deployed `rstudio-workbench` container to your auth domain. The default `rstudio/rstudio-workbench` image has `sssd` installed and started by default. You can include `sssd` configuration in `config.userProvisioning` like so: -```yaml -config: - userProvisioning: - mysssd.conf: - sssd: - config_file_version: 2 - services: nss, pam - domains: rstudio.com - domain/rstudio.com: - id_provider: ldap - auth_provider: ldap -``` -## Licensing + ```yaml + config: + userProvisioning: + mysssd.conf: + sssd: + config_file_version: 2 + services: nss, pam + domains: rstudio.com + domain/rstudio.com: + id_provider: ldap + auth_provider: ldap + ``` -This chart supports activating the product using a license file, license key, or license server. In the case of a license file or key, we recommend against placing it in your values file directly. +## Licensing -### License File +This chart supports activating the product using a *license file*. We recommend storing a license file as a `Secret` and setting the `license.file.secret` and `license.file.secretKey` values accordingly. First, create the secret declaratively with YAML or imperatively using the following command: -`kubectl create secret generic rstudio-workbench-license --from-file=licenses/rstudio-workbench.lic` +```{.bash} +kubectl create secret generic rstudio-workbench-license --from-file=licenses/rstudio-workbench.lic +``` Second, specify the following values: @@ -94,35 +101,68 @@ license: Alternatively, license files can be set during `helm install` with the following argument: -`--set-file license.file.contents=licenses/rstudio-workbench.lic` +```{.bash} +--set-file license.file.contents=licenses/rstudio-workbench.lic +``` + +## Database + +Workbench requires a PostgreSQL database when running in Kubernetes. You must configure a [valid connection URI and a password](https://docs.posit.co/ide/server-pro/database/configuration.html#postgresql) for the product to function correctly. Both the connection URI and password may be specified in the `config` section of `values.yaml`. However, we recommend only adding the connection URI and putting the database password in a Kubernetes `Secret`, which can be [automatically set as an environment variable](#database-password). -### License Key +### Database configuration -Set a license key directly in your values file (`license.key`) or during `helm install` with the argument `--set license.key=XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX`. +Add the following to your `values.yaml`, replacing the `connection-uri` with your database details. + +```yaml +config: + secret: + database.conf: + provider: "postgresql" + connection-uri: "postgres://@:/?sslmode=allow" +``` + +### Database password + +First, create a `Secret` declaratively with YAML or imperatively using the following command (replacing with your actual password): + +```bash +kubectl create secret generic rstudio-workbench-database --from-literal=password=YOURPASSWORDHERE +``` + +Second, specify the following in your `values.yaml`: + +```yaml +pod: + env: + - name: WORKBENCH_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: rstudio-workbench-database + key: password +``` -### License Server +Alternatively, database passwords may be set during `helm install` with the following argument: -Set a license server directly in your values file (`license.server`) or during `helm install` with the argument `--set license.server=`. +`--set config.secret.'database\.conf'.password=""` -## General Principles +## General principles - In most places, we opt to pass Helm values directly into ConfigMaps. We automatically translate these into the - valid `.ini` or `.dcf` file formats required by RStudio Workbench. Those config files and their mount locations are - below. -- If you need to modify the jobs launched by RStudio Workbench, you want to use `job-json-overrides`. There is a section on this below - and [a support article](https://support.rstudio.com/hc/en-us/articles/360051652094-Using-Job-Json-Overrides-with-RStudio-Server-Pro-and-Kubernetes) - on the topic in general. -- The prestart scripts for RStudio Workbench and RStudio Launcher are highly customized to: - - Get the service account information off of the RStudio Workbench pod for use in launching jobs -- RStudio Workbench does not export prometheus metrics on its own. Instead, we run a sidecar graphite exporter - [as described here](https://support.rstudio.com/hc/en-us/articles/360044800273-Monitoring-RStudio-Team-Using-Prometheus-and-Graphite) + valid `.ini` or `.dcf` file formats required by Workbench. + - Those configuration files and their mount locations are covered in the [Configuration files](#configuration-files) section below. +- If you need to modify the jobs launched by Workbench, use `job-json-overrides`. + - Review the [Job Json overrides](#job-json-overrides) section on this below. For general information, see [a support article](https://support.rstudio.com/hc/en-us/articles/360051652094-Using-Job-Json-Overrides-with-RStudio-Server-Pro-and-Kubernetes). +- The prestart scripts for Workbench and Posit Job Launcher are highly customized to get the service account information off of the Workbench pod for use in launching jobs. +- Workbench does not export prometheus metrics on its own. Instead, we run a sidecar graphite exporter. + - This is described in the + [Monitoring Posit Team Using Prometheus and Graphite](https://support.rstudio.com/hc/en-us/articles/360044800273-Monitoring-RStudio-Team-Using-Prometheus-and-Graphite) support article. ## Configuration files -These configuration values all take the form of usual helm values +These configuration values all take the form of usual Helm values so you can set the database password with something like: -``` +```{.bash} ... --set config.secret.database\.conf.password=mypassword ... ``` @@ -136,130 +176,133 @@ config: ``` The names of files are dynamically used, so you can add new files as needed. Beware that some files have default values, -so moving them can have adverse effects. Also, if you use a different mounting paradigm, you will need to change -the `XDG_CONFIG_DIRS` environment variable +so moving them can have adverse effects. Also, if you use a different mounting paradigm, you need to change +the `XDG_CONFIG_DIRS` environment variable. - Session Configuration - These configuration files are mounted into the server and - are mounted into the session pods as well. + are mounted into the session pods. - `repos.conf`, `rsession.conf`, `notifications.conf` - - located in the `config.session.<< name of file >>` helm values - - mounted at `/mnt/session-configmap/rstudio/` -- Session Secret Configuration - - These configuration files are mounted into the server and session pods as well - - `odbc.ini` and other similar shared secrets - - located in `config.sessionSecret.<< name of file>>` helm values - - mounted at `/mnt/session-secret/` -- Secret Configuration - - These configuration files are mounted into the server with more restrictive permissions (0600) + - Located in:
`config.session.<< name of file >>` Helm values + - Mounted at:
`/mnt/session-configmap/rstudio/` +- Session Secret Configuration: + - These configuration files are mounted into the server and session pods. + - `odbc.ini` and other similar shared secrets. + - Located in:
`config.sessionSecret.<< name of file>>` Helm values + - Mounted at:
`/mnt/session-secret/` +- Secret Configuration: + - These configuration files are mounted into the server with more restrictive permissions (0600). - `database.conf`, `openid-client-secret`, `databricks.conf` - - They are located in the `config.secret.<< name of file >>` helm values - - mounted at `/mnt/secret-configmap/rstudio/` -- Server Configuration - - These configuration files are mounted into the server (.ini file format) + - Located in:
`config.secret.<< name of file >>` Helm values + - Mounted at:
`/mnt/secret-configmap/rstudio/` +- Server Configuration: + - These configuration files are mounted into the server (.ini file format). - `rserver.conf`, `launcher.conf`, `jupyter.conf`, `logging.conf` - - They are located at `config.server.<< name of file >>` helm values - - mounted at `/mnt/configmap/rstudio/` -- Server DCF Configuration - - These configuration files are mounted into the server (.dcf file format) + - Located at:
`config.server.<< name of file >>` Helm values + - Mounted at:
`/mnt/configmap/rstudio/` +- Server DCF Configuration: + - These configuration files are mounted into the server (.dcf file format). - `launcher-mounts`, `launcher-env` - - They are located at `config.serverDcf.<< name of file >>` helm values - - included at `/mnt/configmap/rstudio/` -- Profiles Configuration - - These configuration files are mounted into the server (.ini file format) + - Located at:
`config.serverDcf.<< name of file >>` Helm values + - Included at:
`/mnt/configmap/rstudio/` +- Profiles Configuration: + - These configuration files are mounted into the server (.ini file format). - `launcher.kubernetes.profiles.conf` - - They are located at `config.profiles.<< name of file >>` helm values - - included at `/mnt/configmap/rstudio/` - - See the `Profiles` section below for more information -- Prestart - - This is provided by the helm chart in a configmap - - It is mounted into the pod at `/scripts/` - - `prestart-workbench.bash` is used to start workbench - - `prestart-launcher.bash` is used to start launcher -- User Provisioning Configuration - - These configuration files are used for configuring user provisioning (i.e. `sssd`) - - Located at `config.userProvisioning.<< name of file >>` helm values - - Mounted onto `/etc/sssd/conf.d/` with `0600` permissions by default -- Custom Startup Configuration - - `supervisord` service / unit definition `.conf` files - - Located at `config.startupCustom.<< name of file >>` helm values - - Will use the `.ini` file format, by default - - Mounted at `/startup/custom` - - As with all config files above, can override with a verbatim string if desired, like so: -```yaml -config: - startupCustom: - myfile.conf: | - file-used-verbatim -``` -- PAM configuration - - `pam` configuration files - - Located at `config.pam.<< name of file >>` helm values - - Will be mounted verbatim as individual files (using `subPath` mounts) at `/etc/pam.d/<< name of file >>` + - They are located at `config.profiles.<< name of file >>` Helm values + - Included at:
`/mnt/configmap/rstudio/` + - See the [Profiles](#rstudio-profiles) section below for more information. +- Prestart: + - This is provided by the Helm chart in a configmap. + - It is mounted into the pod at `/scripts/`. + - `prestart-workbench.bash` is used to start workbench. + - `prestart-launcher.bash` is used to start launcher. +- User Provisioning Configuration: + - These configuration files are used for configuring user provisioning (i.e., `sssd`). + - Located at:
`config.userProvisioning.<< name of file >>` Helm values + - Mounted onto:
`/etc/sssd/conf.d/` with `0600` permissions by default. +- Custom Startup Configuration: + - `supervisord` service / unit definition `.conf` files. + - Use the `.ini` file format by default. + - Mounted at:
`/startup/custom` + - As with all configuration files above, you can override with a verbatim string if desired: + - Located at:
`config.startupCustom.<< name of file >>` Helm values: + ```yaml + config: + startupCustom: + myfile.conf: | + file-used-verbatim + ``` +- PAM configuration: + - `pam` configuration files. + - Located at:
`config.pam.<< name of file >>` Helm values + - Mounted verbatim as individual files (using `subPath` mounts) at:
`/etc/pam.d/<< name of file >>` -### Configuring R and Python repositories +#### Python repositories -#### R repositories +pip can be configured with `config.session.pip.conf`. To ensure `pip.conf` is mounted into the session pods, it is important that: -R package repositories can be configured with `config.session.repos.conf`. +- `launcher.useTemplates: true` is set +- `pip.conf` settings are listed under `config.session` as shown in the following example for adding Posit Public Package Manager's PyPI: -``` -config: - session: - repos.conf: - CRAN: https://packagemanager.posit.co/cran/__linux__/jammy/latest -``` + ```yaml + launcher: + useTemplates: true -For more information about configuring CRAN repositories in Workbench refer to the [Admin Guide](https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/package_installation.html#cran-repositories). + config: + session: + pip.conf: + "global": + index-url: https://packagemanager.posit.co/pypi/latest/simple + trusted-host: packagemanager.posit.co + ``` -#### Python repositories - -pip can be configured with `config.session.pip.conf`. To ensure `pip.conf` is mounted into the session pods it is important that `launcher.useTemplates: true` is set and `pip.conf` settings are listed under `config.session` like in the example below for adding Posit Public Package Manager's PyPI. +#### R repositories -``` -launcher: - useTemplates: true +R package repositories can be configured with `config.session.repos.conf`: +```yaml config: session: - pip.conf: - "global": - index-url: https://packagemanager.posit.co/pypi/latest/simple - trusted-host: packagemanager.posit.co + repos.conf: + CRAN: https://packagemanager.posit.co/cran/__linux__/jammy/latest ``` -## User Provisioning +For more information about configuring CRAN repositories in Workbench, see the [Posit Workbench Administrator Guide's - Package Installation > CRAN repositories](https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/package_installation.html#cran-repositories) section. -Provisioning users in RStudio Workbench containers is challenging. Session images have users created automatically (with -consistent UIDs / GIDs), but creating users in the Workbench containers is a responsibility that falls to the -administrator today. +## User provisioning + +Provisioning users in Workbench containers is challenging. Session images create users automatically (with +consistent UIDs / GIDs). However, creating users in the Workbench containers is a responsibility that falls to the +administrator. The most common way to provision users is via `sssd`. -The [latest RStudio Workbench container](https://github.com/rstudio/rstudio-docker-products/tree/main/workbench#user-provisioning) +The [latest Workbench container](https://github.com/rstudio/rstudio-docker-products/tree/main/workbench#user-provisioning) has `sssd` included and running by default (see `userProvisioning` configuration files above). -The other way that this can be managed is via a lightweight "startup service" (runs once at startup and then sleeps forever) +The other way that this can be managed is via a lightweight startup service (runs once at startup and then sleeps forever) or a polling service (checks at regular intervals). Either can be written easily in `bash` or another programming language. -However, it is important to be careful of a few points: -- UID / GID consistency: linux usernames and their matching to UID/GID must be consistent across all nodes and across - time. Failing this can cause security issues and access by some users to files they should not be allowed to see -- usernames cannot have `@`. The `@` sign (often used in emails with SSO) is a problem for RStudio Workbench because - some operating systems disallow `@` signs in linux usernames -- `supervisord` is configured by default to exit if any of its child processes exit. If you use `config.startupCustom` - to configure a user management service, be careful that it does not exit unnecessarily +However, it is important to use caution for the following: + +- UID / GID consistency: + - Linux usernames and their matching to UID/GID must be consistent across all nodes and across time. + - Failing can cause security issues and access by some users to access view they should not be allowed to see. +- Usernames cannot have `@`. + - The `@` sign (often used in emails with SSO) is a problem for Workbench because some operating systems disallow `@` signs in linux usernames. +- `supervisord` is configured by default to exit if any of its child processes exit. + - If you use `config.startupCustom` to configure a user management service, be careful that it does not exit unnecessarily. -We do not provide such a service out of the box because we intend for RStudio Workbench to solve this problem in a -future release. Please get in touch with your account representative if you have feedback or questions about this +We do not provide such a service out-of-the box because we intend for Workbench to solve this problem in a +future release. Please contact your account representative if you have feedback or questions about this workflow. ### PAM -When starting sessions on RStudio Workbench, PAM configuration is often very important, even if PAM is not being used as -an authentication mechanism. The RStudio Workbench helm chart allows creating custom PAM files via the `config.pam` +When starting sessions on Workbench, PAM configuration is often very important, even if PAM is not being used as +an authentication mechanism. The Workbench Helm chart allows creating custom PAM files via the `config.pam` values section. -Each key under `config.pam` will become a PAM config file, and will be mounted into `/etc/pam.d/` in the container. For +Each key under `config.pam` becomes a PAM configuration file, and is mounted into `/etc/pam.d/` in the container. For example: ```yaml @@ -273,23 +316,23 @@ config: # will be used verbatim ``` -## RStudio Profiles +## RStudio profiles Profiles are used to define product behavior (in `.ini` file format) based on user and group membership. Sections define whether a set of configurations is applied to a user's jobs based on the following criteria: -- if section header is `[*]`, it applies to all users -- if a user's username is `myusername`, the section `[myusername]` will apply to them -- if a user is in the `allusers` group, then the section `[@allusers]` will apply to them +- If section header is `[*]`, it applies to all users. +- If a user's username is `myusername`, the section `[myusername]` applies to them. +- If a user is in the `allusers` group, then the section `[@allusers]` applies to them The product reads configuration from top to bottom and "last-in-wins" for a given configuration value. ### `/etc/rstudio/profiles` -The `/etc/rstudio/profiles` file enables you to tailor the behavior of sessions on a per-user or per-group basis. See the Workbench Admin Guide [User and Group Profiles](https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/user_and_group_profiles.html) page for more details. +The `/etc/rstudio/profiles` file enables you to tailor the behavior of sessions on a per-user or per-group basis. See the [Posit Workbench Administrator Guide - User and Group Profiles](https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/user_and_group_profiles.html) page for more information. -In the `values.yaml`, the content of `/etc/rstudio/profiles` should be defined in `config.server.profiles`. For example: +In the `values.yaml`, define the content of `/etc/rstudio/profiles` in `config.server.profiles`. For example: ```yaml config: @@ -312,17 +355,17 @@ session-timeout-minutes=60 ### `/etc/rstudio/launcher.kubernetes.profiles.conf` -The `/etc/rstudio/launcher.kubernetes.profiles.conf` contains the configuration of resource limits by user and group when using the Kubernetes Launcher Plugin. In the `values.yaml`, the content of `/etc/rstudio/launcher.kubernetes.profiles.conf ` should be defined in `config.profiles.launcher.kubernetes.profiles.conf`. The `config.profiles` section has a couple of niceties that are added in by default. +The `/etc/rstudio/launcher.kubernetes.profiles.conf` contains the configuration of resource limits by user and group when using the Kubernetes Launcher Plugin. In the `values.yaml`, define the content of `/etc/rstudio/launcher.kubernetes.profiles.conf ` in the `config.profiles.launcher.kubernetes.profiles.conf` file. The `config.profiles` section has a couple of niceties that are added in by default. -- YAML arrays like the following will be "comma-joined." For instance, the following will become: `some-key=value1,value2` +- YAML arrays like the following becomes "comma-joined." For instance, the following becomes: `some-key=value1,value2` -```yaml -some-key: - - value1 - - value2 -``` + ```yaml + some-key: + - value1 + - value2 + ``` -- The `[*]` section will have arrays "appended" to user and group sections, along with "defaults" defined by the chart. +- The `[*]` section has arrays "appended" to user and group sections, along with "defaults" defined by the chart. For example: @@ -339,6 +382,7 @@ config: - value4 - value5 ``` + Becomes: _/etc/rstudio/launcher.kubernetes.profiles.conf_ @@ -350,23 +394,24 @@ some-key: value1,value2 some-key: value1,value2,value3,value4 ``` -> NOTE: this appending/concatenation/array translation behavior only works with the helm chart +:::{.callout-note} +This appending/concatenation/array translation behavior only works with the helm chart. +::: -### Job Json Overrides +### Job Json overrides -If you want to customize the job launch process (i.e. how sessions are defined), you will need to edit the following -configuration: - - modify `config.profiles.launcher\.kubernetes\.profiles\.conf.<< some selector >>.job-json-overrides` - - create an array of maps with the following keys: - - `target`: the "target" part of the job spec to replace - - `name`: a unique identifier (ideally with no spaces) that will become a config filename on disk - - `json`: a YAML value that will be translated directly to JSON and injected into the job spec at `target` +If you want to customize the job launch process (i.e., how sessions are defined), edit the following configuration: -Note that several examples are provided -in [this support article](https://support.rstudio.com/hc/en-us/articles/360051652094-Using-Job-Json-Overrides-with-RStudio-Server-Pro-and-Kubernetes) -(however, examples do not use the helm chart syntax there). +- Modify: + ```yaml + config.profiles.launcher\.kubernetes\.profiles\.conf.<< some selector >>.job-json-overrides` + ``` +- Create an array of maps with the following keys: + - `target`: The "target" part of the job spec to replace. + - `name`: A unique identifier (ideally with no spaces) becomes a configuration filename on disk. + - `json`: A YAML value that is translated directly to JSON and injected into the job spec at `target`. -Alternatively, you can explore the docs in the [helm repository](https://github.com/rstudio/helm/blob/main/docs/customize.md) +Explore the docs in the [Helm repository](https://github.com/rstudio/helm/blob/main/docs/customize.md) for additional information. ```yaml config: @@ -386,10 +431,11 @@ config: - "two-image:tag ``` -## Sealed Secrets -This chart supports the use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) to allow for storing secrets in SCM and to ensure secrets are never leaked via helm. The target cluster must include a `SealedSecret` controller as the controller is responsible for converting a `SealedSecret` to a `Secret`. +## Sealed secrets + +This chart supports the use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) to allow for storing secrets in SCM and to ensure secrets are never leaked via Helm. The target cluster must include a `SealedSecret` controller as the controller is responsible for converting a `SealedSecret` to a `Secret`. -To activate the use of `SealedSecret` templates instead of `Secret` templates in the chart, set `sealedSecret.enabled=true` and ensure the following values are all encrypted. The chart does not support mixing encrypted values with unencrypted values. +To activate the use of `SealedSecret` templates instead of `Secret` templates in the chart, set `sealedSecret.enabled=true` and ensure the following values are all encrypted (the chart does not support mixing encrypted values with unencrypted values): - `config.secret` - `config.sessionSecret` @@ -397,7 +443,7 @@ To activate the use of `SealedSecret` templates instead of `Secret` templates in - `launcherPem` - `secureCookieKey` (or `global.secureCookieKey`) -Use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) disables the chart's auto-generation and reuse capabilities for `launcherPem` and `secureCookieKey`. `launcherPem` is an RSA private key which can be generated via an RSA tool such as helm's [`genPrivateKey`](https://helm.sh/docs/chart_template_guide/function_list/#genprivatekey) function. `secureCookieKey` is typically a UUID which can be generated via a UUID generator such as helm's [`uuidv4`](https://helm.sh/docs/chart_template_guide/function_list/#uuid-functions) function. +Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables the chart's auto-generation and reuse capabilities for `launcherPem` and `secureCookieKey`. `launcherPem` is an RSA private key, which can be generated via an RSA tool such as Helm's [`genPrivateKey`](https://helm.sh/docs/chart_template_guide/function_list/#genprivatekey) function. `secureCookieKey` is typically a UUID, which can be generated via a UUID generator such as Helm's [`uuidv4`](https://helm.sh/docs/chart_template_guide/function_list/#uuid-functions) function. ## Values @@ -466,7 +512,7 @@ Use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) disables | license.file | object | `{"contents":false,"mountPath":"/etc/rstudio-licensing","mountSubPath":false,"secret":false,"secretKey":"license.lic"}` | the file section is used for licensing with a license file | | license.file.contents | bool | `false` | contents is an in-line license file | | license.file.mountPath | string | `"/etc/rstudio-licensing"` | mountPath is the place the license file will be mounted into the container | -| license.file.mountSubPath | bool | `false` | mountSubPath is whether to mount the subPath for the file secret. -- It can be preferable _not_ to enable this, because then updates propagate automatically | +| license.file.mountSubPath | bool | `false` | It can be preferable _not_ to enable this, because then updates propagate automatically | | license.file.secret | bool | `false` | secret is an existing secret with a license file in it | | license.file.secretKey | string | `"license.lic"` | secretKey is the key for the secret to use for the license file | | license.key | string | `nil` | key is the license to use | @@ -487,7 +533,10 @@ Use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) disables | pod.volumes | list | `[]` | volumes is injected as-is into the "volumes:" component of the pod.container spec | | podDisruptionBudget | object | `{}` | Pod disruption budget | | priorityClassName | string | `""` | The pod's priorityClassName | -| prometheusExporter.enabled | bool | `true` | whether the prometheus exporter sidecar should be enabled | +| prometheus.enabled | bool | `true` | The parent setting for whether to enable prometheus metrics. Default is to use the built-in product exporter | +| prometheus.legacy | bool | `false` | Whether to enable the legacy prometheusExporter INSTEAD OF the built-in product exporter. If you change this to `true`, please let us know why! Requires prometheusExporter.enabled=true too | +| prometheus.port | int | `8989` | The port that prometheus will listen on. If legacy=true, then this will be hard-coded to 9108 | +| prometheusExporter.enabled | bool | `true` | DEPRECATED. Whether the prometheus exporter sidecar should be enabled. See prometheus.enabled instead. | | prometheusExporter.image.imagePullPolicy | string | `"IfNotPresent"` | | | prometheusExporter.image.repository | string | `"prom/graphite-exporter"` | | | prometheusExporter.image.tag | string | `"v0.9.0"` | | @@ -545,5 +594,5 @@ Use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) disables | xdgConfigDirsExtra | list | `[]` | A list of additional XDG config dir paths | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0) +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/charts/rstudio-workbench/README.md.gotmpl b/charts/rstudio-workbench/README.md.gotmpl index b6398432..0b4623ca 100644 --- a/charts/rstudio-workbench/README.md.gotmpl +++ b/charts/rstudio-workbench/README.md.gotmpl @@ -8,65 +8,106 @@ {{ template "rstudio.install" . }} -## Required Configuration +## Required configuration -This chart requires the following in order to function: +To function, this chart requires the following: -* A license file, license key, or address of a running license server. See the [Licensing](#licensing) section below for more details. +* A license file. See the [Licensing](#licensing) section below for more details. * A Kubernetes [PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) that contains the home directory for users. - * If `homeStorage.create` is set, a PVC that relies on the default storage class will be created to generate the + * If `homeStorage.create` is set, it creates a Persistent Volume Claim (PVC) that relies on the default storage class to generate the PersistentVolume. Most Kubernetes environments do not have a default storage class that you can use - with `ReadWriteMany` access mode out-of-the-box. In this case, we recommend you disable `homeStorage.create` and - create your own `PersistentVolume` and `PersistentVolumeClaim`, then mount them into the container by specifying + with `ReadWriteMany` access mode out-of-the-box. In this case, we recommend that you: + * Disable `homeStorage.create` and + create your own `PersistentVolume` and `PersistentVolumeClaim`, then + * Mount them into the container by specifying the `pod.volumes` and `pod.volumeMounts` parameters, or by specifying your `PersistentVolumeClaim` using `homeStorage.name` and `homeStorage.mount`. - * If you cannot use a `PersistentVolume` to properly mount your users' home directories, you'll need to mount your + * If you cannot use a `PersistentVolume` to properly mount your users' home directories, mount your data in the container by using a regular [Kubernetes Volume](https://kubernetes.io/docs/concepts/storage/volumes/#nfs), specified in `pod.volumes` and `pod.volumeMounts`. - * If you cannot use a `Volume` to mount the directories, you'll need to manually mount them during container startup + * If you cannot use a `Volume` to mount the directories, manually mount them during container startup with a mechanism similar to what is described below for joining to auth domains. - * If not using `homeStorage.create`, you'll need to configure `config.serverDcf.launcher-mounts` to ensure that the correct mounts are used when users create new sessions. -* If using load balancing (by setting `replicas > 1`), you will need similar storage defined for `sharedStorage` to + * If not using `homeStorage.create`, configure `config.serverDcf.launcher-mounts` to ensure that the correct mounts are used when users create new sessions. +* If using load balancing (by setting `replicas > 1`), you need similar storage defined for `sharedStorage` to store shared project configuration. However, you can also configure the product to store its shared data underneath `/home` by setting `config.server.rserver\.conf.server-shared-storage-path=/home/some-shared-dir`. * A method to join the deployed `rstudio-workbench` container to your auth domain. The default `rstudio/rstudio-workbench` image has `sssd` installed and started by default. You can include `sssd` configuration in `config.userProvisioning` like so: + + ```yaml + config: + userProvisioning: + mysssd.conf: + sssd: + config_file_version: 2 + services: nss, pam + domains: rstudio.com + domain/rstudio.com: + id_provider: ldap + auth_provider: ldap + ``` +{{ template "rstudio.licensing" . }} + +## Database + +Workbench requires a PostgreSQL database when running in Kubernetes. You must configure a [valid connection URI and a password](https://docs.posit.co/ide/server-pro/database/configuration.html#postgresql) for the product to function correctly. Both the connection URI and password may be specified in the `config` section of `values.yaml`. However, we recommend only adding the connection URI and putting the database password in a Kubernetes `Secret`, which can be [automatically set as an environment variable](#database-password). + +### Database configuration + +Add the following to your `values.yaml`, replacing the `connection-uri` with your database details. + ```yaml config: - userProvisioning: - mysssd.conf: - sssd: - config_file_version: 2 - services: nss, pam - domains: rstudio.com - domain/rstudio.com: - id_provider: ldap - auth_provider: ldap + secret: + database.conf: + provider: "postgresql" + connection-uri: "postgres://@:/?sslmode=allow" ``` -{{ template "rstudio.licensing" . }} +### Database password + +First, create a `Secret` declaratively with YAML or imperatively using the following command (replacing with your actual password): + +```bash +kubectl create secret generic {{ .Name }}-database --from-literal=password=YOURPASSWORDHERE +``` -## General Principles +Second, specify the following in your `values.yaml`: + +```yaml +pod: + env: + - name: WORKBENCH_POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Name }}-database + key: password +``` + +Alternatively, database passwords may be set during `helm install` with the following argument: + +`--set config.secret.'database\.conf'.password=""` + +## General principles - In most places, we opt to pass Helm values directly into ConfigMaps. We automatically translate these into the - valid `.ini` or `.dcf` file formats required by RStudio Workbench. Those config files and their mount locations are - below. -- If you need to modify the jobs launched by RStudio Workbench, you want to use `job-json-overrides`. There is a section on this below - and [a support article](https://support.rstudio.com/hc/en-us/articles/360051652094-Using-Job-Json-Overrides-with-RStudio-Server-Pro-and-Kubernetes) - on the topic in general. -- The prestart scripts for RStudio Workbench and RStudio Launcher are highly customized to: - - Get the service account information off of the RStudio Workbench pod for use in launching jobs -- RStudio Workbench does not export prometheus metrics on its own. Instead, we run a sidecar graphite exporter - [as described here](https://support.rstudio.com/hc/en-us/articles/360044800273-Monitoring-RStudio-Team-Using-Prometheus-and-Graphite) + valid `.ini` or `.dcf` file formats required by Workbench. + - Those configuration files and their mount locations are covered in the [Configuration files](#configuration-files) section below. +- If you need to modify the jobs launched by Workbench, use `job-json-overrides`. + - Review the [Job Json overrides](#job-json-overrides) section on this below. For general information, see [a support article](https://support.rstudio.com/hc/en-us/articles/360051652094-Using-Job-Json-Overrides-with-RStudio-Server-Pro-and-Kubernetes). +- The prestart scripts for Workbench and Posit Job Launcher are highly customized to get the service account information off of the Workbench pod for use in launching jobs. +- Workbench does not export prometheus metrics on its own. Instead, we run a sidecar graphite exporter. + - This is described in the + [Monitoring Posit Team Using Prometheus and Graphite](https://support.rstudio.com/hc/en-us/articles/360044800273-Monitoring-RStudio-Team-Using-Prometheus-and-Graphite) support article. ## Configuration files -These configuration values all take the form of usual helm values +These configuration values all take the form of usual Helm values so you can set the database password with something like: -``` +```{.bash} ... --set config.secret.database\.conf.password=mypassword ... ``` @@ -80,130 +121,133 @@ config: ``` The names of files are dynamically used, so you can add new files as needed. Beware that some files have default values, -so moving them can have adverse effects. Also, if you use a different mounting paradigm, you will need to change -the `XDG_CONFIG_DIRS` environment variable +so moving them can have adverse effects. Also, if you use a different mounting paradigm, you need to change +the `XDG_CONFIG_DIRS` environment variable. - Session Configuration - These configuration files are mounted into the server and - are mounted into the session pods as well. + are mounted into the session pods. - `repos.conf`, `rsession.conf`, `notifications.conf` - - located in the `config.session.<< name of file >>` helm values - - mounted at `/mnt/session-configmap/rstudio/` -- Session Secret Configuration - - These configuration files are mounted into the server and session pods as well - - `odbc.ini` and other similar shared secrets - - located in `config.sessionSecret.<< name of file>>` helm values - - mounted at `/mnt/session-secret/` -- Secret Configuration - - These configuration files are mounted into the server with more restrictive permissions (0600) + - Located in:
`config.session.<< name of file >>` Helm values + - Mounted at:
`/mnt/session-configmap/rstudio/` +- Session Secret Configuration: + - These configuration files are mounted into the server and session pods. + - `odbc.ini` and other similar shared secrets. + - Located in:
`config.sessionSecret.<< name of file>>` Helm values + - Mounted at:
`/mnt/session-secret/` +- Secret Configuration: + - These configuration files are mounted into the server with more restrictive permissions (0600). - `database.conf`, `openid-client-secret`, `databricks.conf` - - They are located in the `config.secret.<< name of file >>` helm values - - mounted at `/mnt/secret-configmap/rstudio/` -- Server Configuration - - These configuration files are mounted into the server (.ini file format) + - Located in:
`config.secret.<< name of file >>` Helm values + - Mounted at:
`/mnt/secret-configmap/rstudio/` +- Server Configuration: + - These configuration files are mounted into the server (.ini file format). - `rserver.conf`, `launcher.conf`, `jupyter.conf`, `logging.conf` - - They are located at `config.server.<< name of file >>` helm values - - mounted at `/mnt/configmap/rstudio/` -- Server DCF Configuration - - These configuration files are mounted into the server (.dcf file format) + - Located at:
`config.server.<< name of file >>` Helm values + - Mounted at:
`/mnt/configmap/rstudio/` +- Server DCF Configuration: + - These configuration files are mounted into the server (.dcf file format). - `launcher-mounts`, `launcher-env` - - They are located at `config.serverDcf.<< name of file >>` helm values - - included at `/mnt/configmap/rstudio/` -- Profiles Configuration - - These configuration files are mounted into the server (.ini file format) + - Located at:
`config.serverDcf.<< name of file >>` Helm values + - Included at:
`/mnt/configmap/rstudio/` +- Profiles Configuration: + - These configuration files are mounted into the server (.ini file format). - `launcher.kubernetes.profiles.conf` - - They are located at `config.profiles.<< name of file >>` helm values - - included at `/mnt/configmap/rstudio/` - - See the `Profiles` section below for more information -- Prestart - - This is provided by the helm chart in a configmap - - It is mounted into the pod at `/scripts/` - - `prestart-workbench.bash` is used to start workbench - - `prestart-launcher.bash` is used to start launcher -- User Provisioning Configuration - - These configuration files are used for configuring user provisioning (i.e. `sssd`) - - Located at `config.userProvisioning.<< name of file >>` helm values - - Mounted onto `/etc/sssd/conf.d/` with `0600` permissions by default -- Custom Startup Configuration - - `supervisord` service / unit definition `.conf` files - - Located at `config.startupCustom.<< name of file >>` helm values - - Will use the `.ini` file format, by default - - Mounted at `/startup/custom` - - As with all config files above, can override with a verbatim string if desired, like so: -```yaml -config: - startupCustom: - myfile.conf: | - file-used-verbatim -``` -- PAM configuration - - `pam` configuration files - - Located at `config.pam.<< name of file >>` helm values - - Will be mounted verbatim as individual files (using `subPath` mounts) at `/etc/pam.d/<< name of file >>` + - They are located at `config.profiles.<< name of file >>` Helm values + - Included at:
`/mnt/configmap/rstudio/` + - See the [Profiles](#rstudio-profiles) section below for more information. +- Prestart: + - This is provided by the Helm chart in a configmap. + - It is mounted into the pod at `/scripts/`. + - `prestart-workbench.bash` is used to start workbench. + - `prestart-launcher.bash` is used to start launcher. +- User Provisioning Configuration: + - These configuration files are used for configuring user provisioning (i.e., `sssd`). + - Located at:
`config.userProvisioning.<< name of file >>` Helm values + - Mounted onto:
`/etc/sssd/conf.d/` with `0600` permissions by default. +- Custom Startup Configuration: + - `supervisord` service / unit definition `.conf` files. + - Use the `.ini` file format by default. + - Mounted at:
`/startup/custom` + - As with all configuration files above, you can override with a verbatim string if desired: + - Located at:
`config.startupCustom.<< name of file >>` Helm values: + ```yaml + config: + startupCustom: + myfile.conf: | + file-used-verbatim + ``` +- PAM configuration: + - `pam` configuration files. + - Located at:
`config.pam.<< name of file >>` Helm values + - Mounted verbatim as individual files (using `subPath` mounts) at:
`/etc/pam.d/<< name of file >>` -### Configuring R and Python repositories +#### Python repositories -#### R repositories +pip can be configured with `config.session.pip.conf`. To ensure `pip.conf` is mounted into the session pods, it is important that: -R package repositories can be configured with `config.session.repos.conf`. +- `launcher.useTemplates: true` is set +- `pip.conf` settings are listed under `config.session` as shown in the following example for adding Posit Public Package Manager's PyPI: -``` -config: - session: - repos.conf: - CRAN: https://packagemanager.posit.co/cran/__linux__/jammy/latest -``` + ```yaml + launcher: + useTemplates: true -For more information about configuring CRAN repositories in Workbench refer to the [Admin Guide](https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/package_installation.html#cran-repositories). + config: + session: + pip.conf: + "global": + index-url: https://packagemanager.posit.co/pypi/latest/simple + trusted-host: packagemanager.posit.co + ``` -#### Python repositories +#### R repositories -pip can be configured with `config.session.pip.conf`. To ensure `pip.conf` is mounted into the session pods it is important that `launcher.useTemplates: true` is set and `pip.conf` settings are listed under `config.session` like in the example below for adding Posit Public Package Manager's PyPI. - -``` -launcher: - useTemplates: true +R package repositories can be configured with `config.session.repos.conf`: +```yaml config: session: - pip.conf: - "global": - index-url: https://packagemanager.posit.co/pypi/latest/simple - trusted-host: packagemanager.posit.co + repos.conf: + CRAN: https://packagemanager.posit.co/cran/__linux__/jammy/latest ``` -## User Provisioning +For more information about configuring CRAN repositories in Workbench, see the [Posit Workbench Administrator Guide's - Package Installation > CRAN repositories](https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/package_installation.html#cran-repositories) section. + +## User provisioning -Provisioning users in RStudio Workbench containers is challenging. Session images have users created automatically (with -consistent UIDs / GIDs), but creating users in the Workbench containers is a responsibility that falls to the -administrator today. +Provisioning users in Workbench containers is challenging. Session images create users automatically (with +consistent UIDs / GIDs). However, creating users in the Workbench containers is a responsibility that falls to the +administrator. The most common way to provision users is via `sssd`. -The [latest RStudio Workbench container](https://github.com/rstudio/rstudio-docker-products/tree/main/workbench#user-provisioning) +The [latest Workbench container](https://github.com/rstudio/rstudio-docker-products/tree/main/workbench#user-provisioning) has `sssd` included and running by default (see `userProvisioning` configuration files above). -The other way that this can be managed is via a lightweight "startup service" (runs once at startup and then sleeps forever) +The other way that this can be managed is via a lightweight startup service (runs once at startup and then sleeps forever) or a polling service (checks at regular intervals). Either can be written easily in `bash` or another programming language. -However, it is important to be careful of a few points: -- UID / GID consistency: linux usernames and their matching to UID/GID must be consistent across all nodes and across - time. Failing this can cause security issues and access by some users to files they should not be allowed to see -- usernames cannot have `@`. The `@` sign (often used in emails with SSO) is a problem for RStudio Workbench because - some operating systems disallow `@` signs in linux usernames -- `supervisord` is configured by default to exit if any of its child processes exit. If you use `config.startupCustom` - to configure a user management service, be careful that it does not exit unnecessarily +However, it is important to use caution for the following: -We do not provide such a service out of the box because we intend for RStudio Workbench to solve this problem in a -future release. Please get in touch with your account representative if you have feedback or questions about this +- UID / GID consistency: + - Linux usernames and their matching to UID/GID must be consistent across all nodes and across time. + - Failing can cause security issues and access by some users to access view they should not be allowed to see. +- Usernames cannot have `@`. + - The `@` sign (often used in emails with SSO) is a problem for Workbench because some operating systems disallow `@` signs in linux usernames. +- `supervisord` is configured by default to exit if any of its child processes exit. + - If you use `config.startupCustom` to configure a user management service, be careful that it does not exit unnecessarily. + +We do not provide such a service out-of-the box because we intend for Workbench to solve this problem in a +future release. Please contact your account representative if you have feedback or questions about this workflow. ### PAM -When starting sessions on RStudio Workbench, PAM configuration is often very important, even if PAM is not being used as -an authentication mechanism. The RStudio Workbench helm chart allows creating custom PAM files via the `config.pam` +When starting sessions on Workbench, PAM configuration is often very important, even if PAM is not being used as +an authentication mechanism. The Workbench Helm chart allows creating custom PAM files via the `config.pam` values section. -Each key under `config.pam` will become a PAM config file, and will be mounted into `/etc/pam.d/` in the container. For +Each key under `config.pam` becomes a PAM configuration file, and is mounted into `/etc/pam.d/` in the container. For example: ```yaml @@ -217,23 +261,23 @@ config: # will be used verbatim ``` -## RStudio Profiles +## RStudio profiles Profiles are used to define product behavior (in `.ini` file format) based on user and group membership. Sections define whether a set of configurations is applied to a user's jobs based on the following criteria: -- if section header is `[*]`, it applies to all users -- if a user's username is `myusername`, the section `[myusername]` will apply to them -- if a user is in the `allusers` group, then the section `[@allusers]` will apply to them +- If section header is `[*]`, it applies to all users. +- If a user's username is `myusername`, the section `[myusername]` applies to them. +- If a user is in the `allusers` group, then the section `[@allusers]` applies to them The product reads configuration from top to bottom and "last-in-wins" for a given configuration value. ### `/etc/rstudio/profiles` -The `/etc/rstudio/profiles` file enables you to tailor the behavior of sessions on a per-user or per-group basis. See the Workbench Admin Guide [User and Group Profiles](https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/user_and_group_profiles.html) page for more details. +The `/etc/rstudio/profiles` file enables you to tailor the behavior of sessions on a per-user or per-group basis. See the [Posit Workbench Administrator Guide - User and Group Profiles](https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/user_and_group_profiles.html) page for more information. -In the `values.yaml`, the content of `/etc/rstudio/profiles` should be defined in `config.server.profiles`. For example: +In the `values.yaml`, define the content of `/etc/rstudio/profiles` in `config.server.profiles`. For example: ```yaml config: @@ -256,17 +300,17 @@ session-timeout-minutes=60 ### `/etc/rstudio/launcher.kubernetes.profiles.conf` -The `/etc/rstudio/launcher.kubernetes.profiles.conf` contains the configuration of resource limits by user and group when using the Kubernetes Launcher Plugin. In the `values.yaml`, the content of `/etc/rstudio/launcher.kubernetes.profiles.conf ` should be defined in `config.profiles.launcher.kubernetes.profiles.conf`. The `config.profiles` section has a couple of niceties that are added in by default. +The `/etc/rstudio/launcher.kubernetes.profiles.conf` contains the configuration of resource limits by user and group when using the Kubernetes Launcher Plugin. In the `values.yaml`, define the content of `/etc/rstudio/launcher.kubernetes.profiles.conf ` in the `config.profiles.launcher.kubernetes.profiles.conf` file. The `config.profiles` section has a couple of niceties that are added in by default. -- YAML arrays like the following will be "comma-joined." For instance, the following will become: `some-key=value1,value2` +- YAML arrays like the following becomes "comma-joined." For instance, the following becomes: `some-key=value1,value2` -```yaml -some-key: - - value1 - - value2 -``` + ```yaml + some-key: + - value1 + - value2 + ``` -- The `[*]` section will have arrays "appended" to user and group sections, along with "defaults" defined by the chart. +- The `[*]` section has arrays "appended" to user and group sections, along with "defaults" defined by the chart. For example: @@ -283,6 +327,7 @@ config: - value4 - value5 ``` + Becomes: _/etc/rstudio/launcher.kubernetes.profiles.conf_ @@ -294,23 +339,24 @@ some-key: value1,value2 some-key: value1,value2,value3,value4 ``` -> NOTE: this appending/concatenation/array translation behavior only works with the helm chart +:::{.callout-note} +This appending/concatenation/array translation behavior only works with the helm chart. +::: -### Job Json Overrides +### Job Json overrides -If you want to customize the job launch process (i.e. how sessions are defined), you will need to edit the following -configuration: - - modify `config.profiles.launcher\.kubernetes\.profiles\.conf.<< some selector >>.job-json-overrides` - - create an array of maps with the following keys: - - `target`: the "target" part of the job spec to replace - - `name`: a unique identifier (ideally with no spaces) that will become a config filename on disk - - `json`: a YAML value that will be translated directly to JSON and injected into the job spec at `target` +If you want to customize the job launch process (i.e., how sessions are defined), edit the following configuration: -Note that several examples are provided -in [this support article](https://support.rstudio.com/hc/en-us/articles/360051652094-Using-Job-Json-Overrides-with-RStudio-Server-Pro-and-Kubernetes) -(however, examples do not use the helm chart syntax there). +- Modify: + ```yaml + config.profiles.launcher\.kubernetes\.profiles\.conf.<< some selector >>.job-json-overrides` + ``` +- Create an array of maps with the following keys: + - `target`: The "target" part of the job spec to replace. + - `name`: A unique identifier (ideally with no spaces) becomes a configuration filename on disk. + - `json`: A YAML value that is translated directly to JSON and injected into the job spec at `target`. -Alternatively, you can explore the docs in the [helm repository](https://github.com/rstudio/helm/blob/main/docs/customize.md) +Explore the docs in the [Helm repository](https://github.com/rstudio/helm/blob/main/docs/customize.md) for additional information. ```yaml config: @@ -330,10 +376,11 @@ config: - "two-image:tag ``` -## Sealed Secrets -This chart supports the use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) to allow for storing secrets in SCM and to ensure secrets are never leaked via helm. The target cluster must include a `SealedSecret` controller as the controller is responsible for converting a `SealedSecret` to a `Secret`. +## Sealed secrets + +This chart supports the use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) to allow for storing secrets in SCM and to ensure secrets are never leaked via Helm. The target cluster must include a `SealedSecret` controller as the controller is responsible for converting a `SealedSecret` to a `Secret`. -To activate the use of `SealedSecret` templates instead of `Secret` templates in the chart, set `sealedSecret.enabled=true` and ensure the following values are all encrypted. The chart does not support mixing encrypted values with unencrypted values. +To activate the use of `SealedSecret` templates instead of `Secret` templates in the chart, set `sealedSecret.enabled=true` and ensure the following values are all encrypted (the chart does not support mixing encrypted values with unencrypted values): - `config.secret` - `config.sessionSecret` @@ -341,7 +388,7 @@ To activate the use of `SealedSecret` templates instead of `Secret` templates in - `launcherPem` - `secureCookieKey` (or `global.secureCookieKey`) -Use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) disables the chart's auto-generation and reuse capabilities for `launcherPem` and `secureCookieKey`. `launcherPem` is an RSA private key which can be generated via an RSA tool such as helm's [`genPrivateKey`](https://helm.sh/docs/chart_template_guide/function_list/#genprivatekey) function. `secureCookieKey` is typically a UUID which can be generated via a UUID generator such as helm's [`uuidv4`](https://helm.sh/docs/chart_template_guide/function_list/#uuid-functions) function. +Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables the chart's auto-generation and reuse capabilities for `launcherPem` and `secureCookieKey`. `launcherPem` is an RSA private key, which can be generated via an RSA tool such as Helm's [`genPrivateKey`](https://helm.sh/docs/chart_template_guide/function_list/#genprivatekey) function. `secureCookieKey` is typically a UUID, which can be generated via a UUID generator such as Helm's [`uuidv4`](https://helm.sh/docs/chart_template_guide/function_list/#uuid-functions) function. {{ template "chart.valuesSection" . }} diff --git a/charts/rstudio-workbench/files/job.tpl b/charts/rstudio-workbench/files/job.tpl index 4288b5a6..b89a7a1e 100644 --- a/charts/rstudio-workbench/files/job.tpl +++ b/charts/rstudio-workbench/files/job.tpl @@ -1,6 +1,6 @@ -# Version: 2.3.1 +# Version: 2.5.0 # DO NOT MODIFY the "Version: " key -# Helm Version: v4 +# Helm Version: v1 {{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} apiVersion: batch/v1 kind: Job @@ -18,6 +18,9 @@ metadata: {{- end }} labels: app.kubernetes.io/managed-by: "launcher" + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} {{- with .Job.metadata.job.labels }} {{- range $key, $val := . }} {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} @@ -62,6 +65,9 @@ spec: {{- end }} {{- end }} labels: + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} {{- with .Job.metadata.pod.labels }} {{- range $key, $val := . }} {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} @@ -77,6 +83,7 @@ spec: {{- if .Job.host }} nodeName: {{ toYaml .Job.host }} {{- end }} + enableServiceLinks: {{ if hasKey $templateData.pod "enableServiceLinks" }}{{ $templateData.pod.enableServiceLinks }}{{ else }}false{{ end }} restartPolicy: Never {{- if or $templateData.pod.serviceAccountName .Job.serviceAccountName }} serviceAccountName: {{ .Job.serviceAccountName | default $templateData.pod.serviceAccountName | quote }} @@ -99,7 +106,7 @@ spec: affinity: {{- toYaml . | nindent 8 }} {{- end }} - {{- if or (ne (len .Job.placementConstraints) 0) (ne (len $templateData.pod.nodeSelector) 0) }} + {{- if or (ne (len .Job.placementConstraints) 0) (and $templateData.pod.nodeSelector (ne (len $templateData.pod.nodeSelector) 0)) }} nodeSelector: {{- range .Job.placementConstraints }} {{ .name }}: {{ toYaml .value }} @@ -137,6 +144,48 @@ spec: imagePullSecrets: {{ toYaml . | nindent 12 }} {{- end }} initContainers: + {{- with .Job.initContainers }} + {{- range . }} + - name: {{ toYaml .name }} + image: {{ toYaml .image }} + {{- $isShell := false }} + {{- if .command }} + command: ['/bin/sh'] + {{- $isShell = true }} + {{- else if .exe }} + command: [{{ toYaml .exe }}] + {{- $isShell = false }} + {{- end }} + {{- if or .args $isShell }} + args: + {{- if $isShell }} + - '-c' + {{- if .args }} + - {{ .args | join " " | cat .command | toYaml | indent 12 | trimPrefix (repeat 12 " ") }} + {{- else }} + - {{ .command | toYaml | indent 12 | trimPrefix (repeat 12 " ") }} + {{- end }} + {{- else }} + {{- range .args }} + - {{ toYaml . | indent 12 | trimPrefix (repeat 12 " ") }} + {{- end }} + {{- end }} + {{- end }} + {{- if .environment }} + env: + {{- range .environment }} + - name: {{ toYaml .name | indent 14 | trimPrefix (repeat 14 " ") }} + value: {{ toYaml .value | indent 14 | trimPrefix (repeat 14 " ") }} + {{- end }} + {{- end }} + {{- if .mounts }} + volumeMounts: + {{- range .mounts }} + - {{ nindent 14 (toYaml .) | trim -}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} {{- with .Job.metadata.pod.initContainers }} {{- range . }} - {{ toYaml . | indent 10 | trimPrefix (repeat 10 " ") }} diff --git a/charts/rstudio-workbench/files/service.tpl b/charts/rstudio-workbench/files/service.tpl index 30909985..ad5a9265 100644 --- a/charts/rstudio-workbench/files/service.tpl +++ b/charts/rstudio-workbench/files/service.tpl @@ -1,6 +1,6 @@ -# Version: 2.3.1 +# Version: 2.5.0 # DO NOT MODIFY the "Version: " key -# Helm Version: v4 +# Helm Version: v1 {{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} apiVersion: v1 kind: Service @@ -20,6 +20,9 @@ metadata: labels: app.kubernetes.io/managed-by: "launcher" job-name: {{ toYaml .Job.id }} + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} {{- with .Job.metadata.service.labels }} {{- range $key, $val := . }} {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} diff --git a/charts/rstudio-workbench/templates/NOTES.txt b/charts/rstudio-workbench/templates/NOTES.txt index 51dfb24e..0cf600e8 100644 --- a/charts/rstudio-workbench/templates/NOTES.txt +++ b/charts/rstudio-workbench/templates/NOTES.txt @@ -52,3 +52,9 @@ Please consider removing this configuration value. {{- if .Values.serviceAccountName }} {{- fail "\n\n`serviceAccountName` is no longer used. Use `rbac.serviceAccount.name` instead"}} {{- end }} + +{{- if and (hasKey (get .Values.config.server "rserver.conf") "monitor-graphite-enabled") (not .Values.prometheus.legacy) }} + +{{- print "\n\n`config.server.'rserver/.conf'.monitor-graphite-enabled` is overwritten by `prometheus.legacy=false`. Internal Workbench Prometheus will be used instead." }} + +{{- end }} diff --git a/charts/rstudio-workbench/templates/_helpers.tpl b/charts/rstudio-workbench/templates/_helpers.tpl index d847e766..57f3cf72 100644 --- a/charts/rstudio-workbench/templates/_helpers.tpl +++ b/charts/rstudio-workbench/templates/_helpers.tpl @@ -89,6 +89,10 @@ containers: ports: - containerPort: 8787 name: http + {{- if and .Values.prometheus.enabled (not .Values.prometheus.legacy) }} + - containerPort: {{ .Values.prometheus.port }} + name: metrics + {{- end}} securityContext: {{- toYaml .Values.securityContext | nindent 4 }} volumeMounts: @@ -179,8 +183,8 @@ containers: cpu: "{{ .Values.resources.requests.cpu }}" ephemeral-storage: "{{ .Values.resources.requests.ephemeralStorage }}" {{- end }} - limits: {{- if .Values.resources.limits.enabled }} + limits: memory: "{{ .Values.resources.limits.memory }}" cpu: "{{ .Values.resources.limits.cpu }}" ephemeral-storage: "{{ .Values.resources.limits.ephemeralStorage }}" @@ -206,7 +210,7 @@ containers: {{- toYaml . | nindent 10 }} {{- end }} {{- end }} -{{- if .Values.prometheusExporter.enabled }} +{{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} - name: exporter image: "{{ .Values.prometheusExporter.image.repository }}:{{ .Values.prometheusExporter.image.tag }}" imagePullPolicy: "{{ .Values.prometheusExporter.image.imagePullPolicy }}" @@ -310,7 +314,7 @@ volumes: defaultMode: {{ .Values.config.defaultMode.userProvisioning }} {{- end }} {{ include "rstudio-library.license-volume" (dict "license" ( .Values.license ) "fullName" (include "rstudio-workbench.fullname" .)) }} -{{- if .Values.prometheusExporter.enabled }} +{{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} - name: graphite-exporter-config configMap: name: {{ include "rstudio-workbench.fullname" . }}-graphite diff --git a/charts/rstudio-workbench/templates/configmap-general.yaml b/charts/rstudio-workbench/templates/configmap-general.yaml index b9ded8fc..fa736d57 100644 --- a/charts/rstudio-workbench/templates/configmap-general.yaml +++ b/charts/rstudio-workbench/templates/configmap-general.yaml @@ -70,6 +70,24 @@ data: {{- $overrideDict = mergeOverwrite $licenseServerConf $overrideDict }} {{- end }} {{- $overrideDict = mergeOverwrite $defaultRServerConfig $overrideDict }} +{{- /* default metrics / prometheus configuration */}} + {{- if .Values.prometheus.enabled }} + {{- if .Values.prometheus.legacy }} + {{- /* we set the graphite values as a default, to hide from values.yaml */ -}} + {{- $graphiteDict := dict "rserver.conf" (dict "monitor-graphite-enabled" 1 "monitor-graphite-host" "127.0.0.1" "monitor-graphite-port" 9109 "monitor-graphite-client-id" "rstudio") }} + {{- $overrideDict = mergeOverwrite $graphiteDict $overrideDict }} + {{- else }} + {{- if hasKey $overrideDict "rserver.conf" }} + {{- if hasKey (get $overrideDict "rserver.conf") "monitor-graphite-enabled" }} + {{- /* we explicitly overwrite the graphite endpoint */ -}} + {{- $overrideDict = mergeOverwrite $overrideDict (dict "rserver.conf" (dict "monitor-graphite-enabled" "0")) }} + {{- end }} + {{- end }} + + {{- /* and set a default for the prometheus listener */ -}} + {{- $overrideDict = merge $overrideDict (dict "rserver.conf" ( dict "metrics-enabled" 1 "metrics-port" .Values.prometheus.port))}} + {{- end }} + {{- end }} {{- $overrideDict = mergeOverwrite $defaultLauncherK8sConfig $overrideDict }} {{ include "rstudio-library.config.ini" $overrideDict | indent 2 }} {{/* helper variables to make things here a bit more sane */}} diff --git a/charts/rstudio-workbench/templates/configmap-graphite-exporter.yaml b/charts/rstudio-workbench/templates/configmap-graphite-exporter.yaml index e104e222..a01cec2f 100644 --- a/charts/rstudio-workbench/templates/configmap-graphite-exporter.yaml +++ b/charts/rstudio-workbench/templates/configmap-graphite-exporter.yaml @@ -1,4 +1,4 @@ -{{- if .Values.prometheusExporter.enabled }} +{{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} --- apiVersion: v1 kind: ConfigMap diff --git a/charts/rstudio-workbench/templates/deployment.yaml b/charts/rstudio-workbench/templates/deployment.yaml index ed123099..e88ea1cf 100644 --- a/charts/rstudio-workbench/templates/deployment.yaml +++ b/charts/rstudio-workbench/templates/deployment.yaml @@ -21,15 +21,21 @@ spec: metadata: annotations: checksum/config-general: {{ include (print $.Template.BasePath "/configmap-general.yaml") . | sha256sum }} + {{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} checksum/config-graphite: {{ include (print $.Template.BasePath "/configmap-graphite-exporter.yaml") . | sha256sum }} + {{- end }} checksum/config-prestart: {{ include (print $.Template.BasePath "/configmap-prestart.yaml") . | sha256sum }} checksum/config-secret: {{ include (print $.Template.BasePath "/configmap-secret.yaml") . | sha256sum }} checksum/config-session: {{ include (print $.Template.BasePath "/configmap-session.yaml") . | sha256sum }} - {{- if .Values.prometheusExporter.enabled }} + {{- if .Values.prometheus }} prometheus.io/scrape: "true" prometheus.io/path: "/metrics" + {{- if and .Values.prometheus.legacy .Values.prometheusExporter.enabled }} prometheus.io/port: "9108" + {{- else }} + prometheus.io/port: {{ .Values.prometheus.port | quote }} {{- end }} + {{- end }} {{- include "rstudio-workbench.pod.annotations" . | nindent 8 }} labels: {{- include "rstudio-workbench.selectorLabels" . | nindent 8 }} diff --git a/charts/rstudio-workbench/templates/service-monitor.yaml b/charts/rstudio-workbench/templates/service-monitor.yaml index 4136f5a5..0210eaa7 100644 --- a/charts/rstudio-workbench/templates/service-monitor.yaml +++ b/charts/rstudio-workbench/templates/service-monitor.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.prometheusExporter.enabled .Values.serviceMonitor.enabled -}} +{{- if and .Values.prometheus.enabled .Values.serviceMonitor.enabled -}} apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: diff --git a/charts/rstudio-workbench/templates/svc.yaml b/charts/rstudio-workbench/templates/svc.yaml index 713a54db..427eecf3 100644 --- a/charts/rstudio-workbench/templates/svc.yaml +++ b/charts/rstudio-workbench/templates/svc.yaml @@ -28,7 +28,12 @@ spec: nodePort: {{ .Values.service.nodePort }} {{- end }} targetPort: 8787 - {{- if .Values.prometheusExporter.enabled }} + {{- if .Values.prometheus.enabled }} - name: metrics + targetPort: metrics + {{- if .Values.prometheus.legacy }} port: 9108 + {{- else }} + port: {{ .Values.prometheus.port }} + {{- end }} {{- end }} diff --git a/charts/rstudio-workbench/templates/tests/test-verify-installation.yaml b/charts/rstudio-workbench/templates/tests/test-verify-installation.yaml deleted file mode 100644 index 27bec28f..00000000 --- a/charts/rstudio-workbench/templates/tests/test-verify-installation.yaml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: {{ include "rstudio-workbench.fullname" . }}-test - annotations: - "helm.sh/hook": test -spec: - {{/** - * NOTE: In the case where a service account was in use and - * then later removed, the behavior of kubernetes is to - * leave the `serviceAccount` / `serviceAccountName` value - * unchanged unless explicitly overwritten with an empty - * string. See linked issues tracing backward from: - * https://github.com/kubernetes/kubernetes/issues/108208#issuecomment-1262269204 - * and also the "Note" callout at the end of this section: - * https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-multiple-service-accounts - */}} - {{- $serviceAccountName := .Values.rbac.serviceAccount.name | default (include "rstudio-workbench.fullname" .)}} - {{- if or .Values.rbac.create (.Values.rbac.serviceAccount.name) }} - serviceAccountName: {{ $serviceAccountName }} - {{- else }} - serviceAccountName: {{ .Values.rbac.serviceAccount.name | toString | quote }} - {{- end }} - {{- with .Values.image.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 4 }} - {{- end }} - shareProcessNamespace: {{ .Values.shareProcessNamespace }} - restartPolicy: Never - {{- $topLevelParams := dict "diagnostics" (dict "enabled" true) "userCreate" true }} - {{- $disabledObject := dict "enabled" false }} - {{- $readinessProbe := dict "readinessProbe" $disabledObject }} - {{- $livenessProbe := dict "livenessProbe" $disabledObject }} - {{- $startupProbe := dict "startupProbe" $disabledObject }} - {{- $prometheusExporter := dict "prometheusExporter" $disabledObject }} - {{- $overrideDict := . | deepCopy }} - {{- $_ := mergeOverwrite $overrideDict.Values $prometheusExporter $startupProbe $livenessProbe $readinessProbe $topLevelParams }} -{{ include "rstudio-workbench.containers" $overrideDict | indent 2 }} diff --git a/charts/rstudio-workbench/values.yaml b/charts/rstudio-workbench/values.yaml index 7ecdb6e8..cecc98b7 100644 --- a/charts/rstudio-workbench/values.yaml +++ b/charts/rstudio-workbench/values.yaml @@ -321,8 +321,17 @@ pod: # -- The termination grace period seconds allowed for the pod before shutdown terminationGracePeriodSeconds: 120 +prometheus: + # -- The parent setting for whether to enable prometheus metrics. Default is to use the built-in product exporter + enabled: true + # -- The port that prometheus will listen on. If legacy=true, then this will be hard-coded to 9108 + port: 8989 + # -- Whether to enable the legacy prometheusExporter INSTEAD OF the built-in product exporter. If you change this to + # `true`, please let us know why! Requires prometheusExporter.enabled=true too + legacy: false + prometheusExporter: - # -- whether the prometheus exporter sidecar should be enabled + # -- DEPRECATED. Whether the prometheus exporter sidecar should be enabled. See prometheus.enabled instead. enabled: true # -- Yaml that defines the graphite exporter mapping. null by default, which uses the embedded / default mapping yaml file mappingYaml: null @@ -435,10 +444,6 @@ config: launcher-port: 5559 launcher-sessions-enabled: 1 launcher-default-cluster: Kubernetes - monitor-graphite-enabled: 1 - monitor-graphite-host: 127.0.0.1 - monitor-graphite-port: 9109 - monitor-graphite-client-id: rstudio launcher.conf: server: address: 127.0.0.1 @@ -458,14 +463,28 @@ config: default-session-cluster: Kubernetes vscode.conf: enabled: 1 - exe: /opt/code-server/bin/code-server - args: --host=0.0.0.0 + session-timeout-kill-hours: 12 + vscode.extensions.conf: | + quarto.quarto + posit.shiny + posit.publisher vscode-user-settings.json: | { "terminal.integrated.shell.linux": "/bin/bash", "extensions.autoUpdate": false, "extensions.autoCheckUpdates": false } + # positron.conf: + # enabled: 1 + # positron.extensions.conf: | + # posit.shiny + # posit.publisher + # positron-user-settings.json: | + # { + # "terminal.integrated.shell.linux": "/bin/bash", + # "extensions.autoUpdate": false, + # "extensions.autoCheckUpdates": false + # } logging.conf: "*": log-level: info diff --git a/charts/posit-chronicle/ci/empty-values.yaml b/ci/posit-chronicle/install/empty-values.yaml similarity index 100% rename from charts/posit-chronicle/ci/empty-values.yaml rename to ci/posit-chronicle/install/empty-values.yaml diff --git a/charts/posit-chronicle/ci/complex-values.yaml b/ci/posit-chronicle/lint/complex-values.yaml similarity index 100% rename from charts/posit-chronicle/ci/complex-values.yaml rename to ci/posit-chronicle/lint/complex-values.yaml diff --git a/charts/rstudio-connect/ci/empty-values.yaml b/ci/posit-chronicle/lint/empty-values.yaml similarity index 100% rename from charts/rstudio-connect/ci/empty-values.yaml rename to ci/posit-chronicle/lint/empty-values.yaml diff --git a/charts/posit-chronicle/ci/no-local-storage-values.yaml b/ci/posit-chronicle/lint/no-local-storage-values.yaml similarity index 100% rename from charts/posit-chronicle/ci/no-local-storage-values.yaml rename to ci/posit-chronicle/lint/no-local-storage-values.yaml diff --git a/charts/posit-chronicle/ci/simple-values.yaml b/ci/posit-chronicle/lint/simple-values.yaml similarity index 100% rename from charts/posit-chronicle/ci/simple-values.yaml rename to ci/posit-chronicle/lint/simple-values.yaml diff --git a/ci/rstudio-connect/install/license-file-values.yaml b/ci/rstudio-connect/install/license-file-values.yaml new file mode 100644 index 00000000..07ed08b3 --- /dev/null +++ b/ci/rstudio-connect/install/license-file-values.yaml @@ -0,0 +1,4 @@ +license: + file: + secret: pct-license + secretKey: pct.lic diff --git a/charts/rstudio-connect/ci/complex-values.yaml b/ci/rstudio-connect/lint/complex-values.yaml similarity index 97% rename from charts/rstudio-connect/ci/complex-values.yaml rename to ci/rstudio-connect/lint/complex-values.yaml index 852e819b..b798dc39 100644 --- a/charts/rstudio-connect/ci/complex-values.yaml +++ b/ci/rstudio-connect/lint/complex-values.yaml @@ -50,7 +50,7 @@ pod: imagePullPolicy: "IfNotPresent" # This will spin up the chronicle-agent sidecar container - name: chronicle-agent - image: ghcr.io/rstudio/chronicle-agent:2024.03.0 + image: ghcr.io/rstudio/chronicle-agent:2024.11.0 env: - name: CHRONICLE_SERVER_ADDRESS value: "http://chronicle-server.default" @@ -110,12 +110,10 @@ replicas: 2 resources: requests: - enabled: false memory: "1Gi" cpu: "100m" ephemeralStorage: "100Mi" limits: - enabled: false memory: "2Gi" cpu: "2000m" ephemeralStorage: "200Mi" diff --git a/charts/rstudio-connect/ci/deprecated-values.yaml b/ci/rstudio-connect/lint/deprecated-values.yaml similarity index 100% rename from charts/rstudio-connect/ci/deprecated-values.yaml rename to ci/rstudio-connect/lint/deprecated-values.yaml diff --git a/charts/rstudio-launcher-rbac/ci/empty-values.yaml b/ci/rstudio-connect/lint/empty-values.yaml similarity index 100% rename from charts/rstudio-launcher-rbac/ci/empty-values.yaml rename to ci/rstudio-connect/lint/empty-values.yaml diff --git a/charts/rstudio-connect/ci/ingress-values.yaml b/ci/rstudio-connect/lint/ingress-values.yaml similarity index 100% rename from charts/rstudio-connect/ci/ingress-values.yaml rename to ci/rstudio-connect/lint/ingress-values.yaml diff --git a/charts/rstudio-connect/ci/ingress2-values.yaml b/ci/rstudio-connect/lint/ingress2-values.yaml similarity index 100% rename from charts/rstudio-connect/ci/ingress2-values.yaml rename to ci/rstudio-connect/lint/ingress2-values.yaml diff --git a/charts/rstudio-connect/ci/launcher-advanced-values.yaml b/ci/rstudio-connect/lint/launcher-advanced-values.yaml similarity index 95% rename from charts/rstudio-connect/ci/launcher-advanced-values.yaml rename to ci/rstudio-connect/lint/launcher-advanced-values.yaml index 5318e6d6..014df573 100644 --- a/charts/rstudio-connect/ci/launcher-advanced-values.yaml +++ b/ci/rstudio-connect/lint/launcher-advanced-values.yaml @@ -2,6 +2,7 @@ rbac: create: true serviceAccount: create: true + name: "connect-service-account" securityContext: null sharedStorage: create: true diff --git a/charts/rstudio-connect/ci/launcher-advanced2-values.yaml b/ci/rstudio-connect/lint/launcher-advanced2-values.yaml similarity index 100% rename from charts/rstudio-connect/ci/launcher-advanced2-values.yaml rename to ci/rstudio-connect/lint/launcher-advanced2-values.yaml diff --git a/charts/rstudio-connect/ci/launcher-advanced3-values.yaml b/ci/rstudio-connect/lint/launcher-advanced3-values.yaml similarity index 100% rename from charts/rstudio-connect/ci/launcher-advanced3-values.yaml rename to ci/rstudio-connect/lint/launcher-advanced3-values.yaml diff --git a/charts/rstudio-connect/ci/launcher-template-values.yaml b/ci/rstudio-connect/lint/launcher-template-values.yaml similarity index 100% rename from charts/rstudio-connect/ci/launcher-template-values.yaml rename to ci/rstudio-connect/lint/launcher-template-values.yaml diff --git a/charts/rstudio-connect/ci/launcher-values.yaml b/ci/rstudio-connect/lint/launcher-values.yaml similarity index 100% rename from charts/rstudio-connect/ci/launcher-values.yaml rename to ci/rstudio-connect/lint/launcher-values.yaml diff --git a/charts/rstudio-connect/ci/simple-values.yaml b/ci/rstudio-connect/lint/simple-values.yaml similarity index 100% rename from charts/rstudio-connect/ci/simple-values.yaml rename to ci/rstudio-connect/lint/simple-values.yaml diff --git a/ci/rstudio-connect/tests/service-accounts_test.yaml b/ci/rstudio-connect/tests/service-accounts_test.yaml new file mode 100644 index 00000000..9e68cc65 --- /dev/null +++ b/ci/rstudio-connect/tests/service-accounts_test.yaml @@ -0,0 +1,32 @@ +suite: Connect Service Accounts +templates: + - configmap.yaml + - configmap-prestart.yaml + - deployment.yaml +tests: + - it: should set the Connect pod service account when the launcher is enabled + template: deployment.yaml + set: + launcher: + enabled: true + rbac: + create: true + serviceAccount: + name: "connect-service-account" + asserts: + - equal: + path: "spec.template.spec.serviceAccountName" + value: "connect-service-account" + - it: should set the Connect pod service account when the launcher is not enabled + template: deployment.yaml + set: + launcher: + enabled: false + rbac: + create: true + serviceAccount: + name: "connect-service-account" + asserts: + - equal: + path: "spec.template.spec.serviceAccountName" + value: "connect-service-account" diff --git a/charts/rstudio-pm/ci/empty-values.yaml b/ci/rstudio-launcher-rbac/install/empty-values.yaml similarity index 100% rename from charts/rstudio-pm/ci/empty-values.yaml rename to ci/rstudio-launcher-rbac/install/empty-values.yaml diff --git a/charts/rstudio-launcher-rbac/ci/all-values.yaml b/ci/rstudio-launcher-rbac/lint/all-values.yaml similarity index 100% rename from charts/rstudio-launcher-rbac/ci/all-values.yaml rename to ci/rstudio-launcher-rbac/lint/all-values.yaml diff --git a/charts/rstudio-workbench/ci/empty-values.yaml b/ci/rstudio-launcher-rbac/lint/empty-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/empty-values.yaml rename to ci/rstudio-launcher-rbac/lint/empty-values.yaml diff --git a/charts/rstudio-launcher-rbac/ci/just-yaml-values.yaml b/ci/rstudio-launcher-rbac/lint/just-yaml-values.yaml similarity index 100% rename from charts/rstudio-launcher-rbac/ci/just-yaml-values.yaml rename to ci/rstudio-launcher-rbac/lint/just-yaml-values.yaml diff --git a/charts/rstudio-launcher-rbac/ci/no-release-ns-values.yaml b/ci/rstudio-launcher-rbac/lint/no-release-ns-values.yaml similarity index 100% rename from charts/rstudio-launcher-rbac/ci/no-release-ns-values.yaml rename to ci/rstudio-launcher-rbac/lint/no-release-ns-values.yaml diff --git a/charts/rstudio-launcher-rbac/ci/no-sa-values.yaml b/ci/rstudio-launcher-rbac/lint/no-sa-values.yaml similarity index 100% rename from charts/rstudio-launcher-rbac/ci/no-sa-values.yaml rename to ci/rstudio-launcher-rbac/lint/no-sa-values.yaml diff --git a/charts/rstudio-launcher-rbac/ci/simple-values.yaml b/ci/rstudio-launcher-rbac/lint/simple-values.yaml similarity index 100% rename from charts/rstudio-launcher-rbac/ci/simple-values.yaml rename to ci/rstudio-launcher-rbac/lint/simple-values.yaml diff --git a/ci/rstudio-pm/install/license-file-values.yaml b/ci/rstudio-pm/install/license-file-values.yaml new file mode 100644 index 00000000..e2f9ec51 --- /dev/null +++ b/ci/rstudio-pm/install/license-file-values.yaml @@ -0,0 +1,4 @@ +license: + file: + secret: ppm-license + secretKey: ppm.lic diff --git a/charts/rstudio-pm/ci/all-values.yaml b/ci/rstudio-pm/lint/all-values.yaml similarity index 96% rename from charts/rstudio-pm/ci/all-values.yaml rename to ci/rstudio-pm/lint/all-values.yaml index efa2c9b8..4db74076 100644 --- a/charts/rstudio-pm/ci/all-values.yaml +++ b/ci/rstudio-pm/lint/all-values.yaml @@ -79,7 +79,7 @@ priorityClassName: someval # Testing with the chronicle-agent sidecar container extraContainers: - name: chronicle-agent - image: ghcr.io/rstudio/chronicle-agent:2024.03.0 + image: ghcr.io/rstudio/chronicle-agent:2024.11.0 imagePullPolicy: Always env: - name: CHRONICLE_SERVER_ADDRESS diff --git a/ci/rstudio-pm/lint/empty-values.yaml b/ci/rstudio-pm/lint/empty-values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/charts/rstudio-pm/ci/ingress-values.yaml b/ci/rstudio-pm/lint/ingress-values.yaml similarity index 100% rename from charts/rstudio-pm/ci/ingress-values.yaml rename to ci/rstudio-pm/lint/ingress-values.yaml diff --git a/charts/rstudio-pm/ci/ingress2-values.yaml b/ci/rstudio-pm/lint/ingress2-values.yaml similarity index 100% rename from charts/rstudio-pm/ci/ingress2-values.yaml rename to ci/rstudio-pm/lint/ingress2-values.yaml diff --git a/charts/rstudio-pm/ci/simple-values.yaml b/ci/rstudio-pm/lint/simple-values.yaml similarity index 100% rename from charts/rstudio-pm/ci/simple-values.yaml rename to ci/rstudio-pm/lint/simple-values.yaml diff --git a/ci/rstudio-workbench/install/basic-ingress-values.yaml b/ci/rstudio-workbench/install/basic-ingress-values.yaml new file mode 100644 index 00000000..00f08bef --- /dev/null +++ b/ci/rstudio-workbench/install/basic-ingress-values.yaml @@ -0,0 +1,14 @@ +license: + file: + secret: pwb-license + secretKey: pwb.lic + +ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: traefik + + hosts: + - host: workbench.rstudio.com + paths: + - path: /test/ diff --git a/ci/rstudio-workbench/install/basic-service-account-values.yaml b/ci/rstudio-workbench/install/basic-service-account-values.yaml new file mode 100644 index 00000000..698d48f0 --- /dev/null +++ b/ci/rstudio-workbench/install/basic-service-account-values.yaml @@ -0,0 +1,10 @@ +license: + file: + secret: pwb-license + secretKey: pwb.lic + +rbac: + create: true + serviceAccount: + name: test-sa + create: true diff --git a/ci/rstudio-workbench/install/launcher-template-values.yaml b/ci/rstudio-workbench/install/launcher-template-values.yaml new file mode 100644 index 00000000..c21e71d0 --- /dev/null +++ b/ci/rstudio-workbench/install/launcher-template-values.yaml @@ -0,0 +1,58 @@ +license: + file: + secret: pwb-license + secretKey: pwb.lic + +config: + sessionSecret: + example-file.json: '{"some-contents": "test"}' +launcher: + enabled: true + useTemplates: true + templateValues: + service: + type: ClusterIP + annotations: + five: six + job: + ttlSecondsAfterFinished: 99 + annotations: + seven: eight + labels: + nine: ten + pod: + serviceAccountName: test + annotations: + one: two + labels: + three: four + volumes: + - name: test + emptyDir: {} + volumeMounts: + - name: test + mountPath: /tmp/mnt + env: + - name: SOME_ENV_VAR + value: the-env-var-value + securityContext: + runAsUser: 999 + defaultSecurityContext: + fsGroupChangePolicy: "Always" + runAsGroup: 999 + containerSecurityContext: + privileged: false + tolerations: + - key: "kubernetes.azure.com/scalesetpriority" + operator: "Equal" + value: "spot" + effect: "NoSchedule" + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: "kubernetes.azure.com/scalesetpriority" + operator: In + values: + - "spot" diff --git a/ci/rstudio-workbench/install/license-file-values.yaml b/ci/rstudio-workbench/install/license-file-values.yaml new file mode 100644 index 00000000..ca1c194a --- /dev/null +++ b/ci/rstudio-workbench/install/license-file-values.yaml @@ -0,0 +1,4 @@ +license: + file: + secret: pwb-license + secretKey: pwb.lic diff --git a/ci/rstudio-workbench/install/user-create-values.yaml b/ci/rstudio-workbench/install/user-create-values.yaml new file mode 100644 index 00000000..a269de48 --- /dev/null +++ b/ci/rstudio-workbench/install/user-create-values.yaml @@ -0,0 +1,8 @@ +license: + file: + secret: pwb-license + secretKey: pwb.lic + +userCreate: true +userName: jforest-test +userPassword: djhkjhij870jjbJye diff --git a/charts/rstudio-workbench/ci/complex-values.yaml b/ci/rstudio-workbench/lint/complex-values.yaml similarity index 98% rename from charts/rstudio-workbench/ci/complex-values.yaml rename to ci/rstudio-workbench/lint/complex-values.yaml index ccd3f6b3..3755e6aa 100644 --- a/charts/rstudio-workbench/ci/complex-values.yaml +++ b/ci/rstudio-workbench/lint/complex-values.yaml @@ -36,7 +36,7 @@ pod: # This will spin up the chronicle-agent sidecar container sidecar: - name: chronicle-agent - image: ghcr.io/rstudio/chronicle-agent:2024.03.0 + image: ghcr.io/rstudio/chronicle-agent:2024.11.0 volumeMounts: - name: logs mountPath: "/var/lib/rstudio-server/audit" diff --git a/charts/rstudio-workbench/ci/default-sa-values.yaml b/ci/rstudio-workbench/lint/default-sa-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/default-sa-values.yaml rename to ci/rstudio-workbench/lint/default-sa-values.yaml diff --git a/ci/rstudio-workbench/lint/empty-values.yaml b/ci/rstudio-workbench/lint/empty-values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/charts/rstudio-workbench/ci/ingress-values.yaml b/ci/rstudio-workbench/lint/ingress-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/ingress-values.yaml rename to ci/rstudio-workbench/lint/ingress-values.yaml diff --git a/charts/rstudio-workbench/ci/ingress2-values.yaml b/ci/rstudio-workbench/lint/ingress2-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/ingress2-values.yaml rename to ci/rstudio-workbench/lint/ingress2-values.yaml diff --git a/charts/rstudio-workbench/ci/launcher-template-values.yaml b/ci/rstudio-workbench/lint/launcher-template-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/launcher-template-values.yaml rename to ci/rstudio-workbench/lint/launcher-template-values.yaml diff --git a/charts/rstudio-workbench/ci/license-file-secret-values.yaml b/ci/rstudio-workbench/lint/license-file-secret-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/license-file-secret-values.yaml rename to ci/rstudio-workbench/lint/license-file-secret-values.yaml diff --git a/charts/rstudio-workbench/ci/license-file-values.yaml b/ci/rstudio-workbench/lint/license-file-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/license-file-values.yaml rename to ci/rstudio-workbench/lint/license-file-values.yaml diff --git a/charts/rstudio-workbench/ci/license-server-values.yaml b/ci/rstudio-workbench/lint/license-server-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/license-server-values.yaml rename to ci/rstudio-workbench/lint/license-server-values.yaml diff --git a/charts/rstudio-workbench/ci/license-values.yaml b/ci/rstudio-workbench/lint/license-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/license-values.yaml rename to ci/rstudio-workbench/lint/license-values.yaml diff --git a/charts/rstudio-workbench/ci/other-complex-values.yaml b/ci/rstudio-workbench/lint/other-complex-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/other-complex-values.yaml rename to ci/rstudio-workbench/lint/other-complex-values.yaml diff --git a/charts/rstudio-workbench/ci/overrides-values-new.yaml b/ci/rstudio-workbench/lint/overrides-values-new.yaml similarity index 100% rename from charts/rstudio-workbench/ci/overrides-values-new.yaml rename to ci/rstudio-workbench/lint/overrides-values-new.yaml diff --git a/charts/rstudio-workbench/ci/overrides-values.yaml b/ci/rstudio-workbench/lint/overrides-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/overrides-values.yaml rename to ci/rstudio-workbench/lint/overrides-values.yaml diff --git a/charts/rstudio-workbench/ci/simple-profiles-values.yaml b/ci/rstudio-workbench/lint/simple-profiles-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/simple-profiles-values.yaml rename to ci/rstudio-workbench/lint/simple-profiles-values.yaml diff --git a/charts/rstudio-workbench/ci/simple-values.yaml b/ci/rstudio-workbench/lint/simple-values.yaml similarity index 100% rename from charts/rstudio-workbench/ci/simple-values.yaml rename to ci/rstudio-workbench/lint/simple-values.yaml diff --git a/ci/rstudio-workbench/tests/deployment_test.yaml b/ci/rstudio-workbench/tests/deployment_test.yaml new file mode 100644 index 00000000..c0c9b984 --- /dev/null +++ b/ci/rstudio-workbench/tests/deployment_test.yaml @@ -0,0 +1,730 @@ +suite: Workbench Deployment +templates: + - configmap-general.yaml + - configmap-prestart.yaml + - configmap-secret.yaml + - configmap-session.yaml + - deployment.yaml +tests: + - it: should not specify the RollingUpdate configuration if the strategy type is not RollingUpdate + template: deployment.yaml + set: + strategy: + type: "Recreate" + asserts: + - notExists: + path: "spec.strategy.rollingUpdate" + - it: should specify the RollingUpdate configuration if the strategy type is RollingUpdate + template: deployment.yaml + set: + strategy: + type: "RollingUpdate" + rollingUpdate: + maxUnavailable: 1 + maxSurge: "50%" + asserts: + - equal: + path: "spec.strategy.type" + value: "RollingUpdate" + - equal: + path: "spec.strategy.rollingUpdate.maxUnavailable" + value: 1 + - equal: + path: "spec.strategy.rollingUpdate.maxSurge" + value: "50%" + - it: should specify the diagnostic env vars if diagnostics is enabled + template: deployment.yaml + set: + diagnostics: + enabled: true + directory: "/var/log/rstudio-workbench" + asserts: + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="DIAGNOSTIC_DIR")].value' + value: "/var/log/rstudio-workbench" + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="DIAGNOSTIC_ENABLE")].value' + value: "true" + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="DIAGNOSTIC_ONLY")].value' + value: "true" + - it: should not specify the diagnostic env vars if diagnostics is not enabled + template: deployment.yaml + set: + diagnostics: + enabled: false + directory: "/var/log/rstudio-workbench" + asserts: + - notExists: + path: 'spec.template.spec.containers[0].env[?(@.name=="DIAGNOSTIC_DIR")]' + - notExists: + path: 'spec.template.spec.containers[0].env[?(@.name=="DIAGNOSTIC_ENABLE")]' + - notExists: + path: 'spec.template.spec.containers[0].env[?(@.name=="DIAGNOSTIC_ONLY")]' + - it: should set the RSTUDIO_LAUNCHER_STARTUP_HEALTHCHECK_ARGS env var if launcher.kubernetesHealthCheck.enabled is true + template: deployment.yaml + set: + launcher: + kubernetesHealthCheck: + enabled: true + extraCurlArgs: ["-fsSL", "-k"] + asserts: + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSTUDIO_LAUNCHER_STARTUP_HEALTH_CHECK_ARGS")].value' + value: "-fsSL -k" + - notExists: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSTUDIO_LAUNCHER_STARTUP_HEALTH_CHECK")]' + - it: should set the RSTUDIO_LAUNCHER_STARTUP_HEALTH_CHECK to disabled if launcher.kubernetesHealthCheck.enabled is false + template: deployment.yaml + set: + launcher: + kubernetesHealthCheck: + enabled: false + asserts: + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSTUDIO_LAUNCHER_STARTUP_HEALTH_CHECK")].value' + value: "disabled" + - it: should set the ENV vars for user creation if userCreate is true + template: deployment.yaml + set: + userCreate: true + userName: "testuser" + userPassword: "testpassword" + userUid: 1000 + asserts: + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSW_TESTUSER")].value' + value: "testuser" + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSW_TESTUSER_PASSWD")].value' + value: "testpassword" + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSW_TESTUSER_UID")].value' + value: "1000" + - it: should set the RSW_TESTUSER ENV var to an empty string if userCreate is false + template: deployment.yaml + set: + userCreate: false + userName: "testuser" + userPassword: "testpassword" + userUid: 1000 + asserts: + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSW_TESTUSER")].value' + value: "" + - notExists: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSW_TESTUSER_PASSWD")]' + - notExists: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSW_TESTUSER_UID")]' + - it: should set the RSW_LOAD_BALANCING env var to true if replicas > 1 + template: deployment.yaml + set: + replicas: 2 + asserts: + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSW_LOAD_BALANCING")].value' + value: "true" + - it: should not set the RSW_LOAD_BALANCING env var replicas = 1 + template: deployment.yaml + set: + replicas: 1 + asserts: + - notExists: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSW_LOAD_BALANCING")]' + - it: should set the RSW_LOAD_BALANCING env var to true if loadBalancer.forceEnabled is true even if replicas = 1 + template: deployment.yaml + set: + replicas: 1 + loadBalancer: + forceEnabled: true + asserts: + - equal: + path: 'spec.template.spec.containers[0].env[?(@.name=="RSW_LOAD_BALANCING")].value' + value: "true" + - it: should specify a volumeMount and a volume for sharedStorage if sharedStorage.create is true + template: deployment.yaml + set: + sharedStorage: + create: true + path: "/mnt/shared" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-shared-storage")].mountPath' + value: "/mnt/shared" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-shared-storage")].persistentVolumeClaim.claimName' + value: "RELEASE-NAME-rstudio-workbench-shared-storage" + - it: should specify a volumeMount and a volume for sharedStorage if sharedStorage.mount is true + template: deployment.yaml + set: + sharedStorage: + mount: true + path: "/mnt/shared" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-shared-storage")].mountPath' + value: "/mnt/shared" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-shared-storage")].persistentVolumeClaim.claimName' + value: "RELEASE-NAME-rstudio-workbench-shared-storage" + - it: should specify a volumeMount and a volume for homeStorage if homeStorage.create is true + template: deployment.yaml + set: + homeStorage: + create: true + path: "/mnt/shared" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-home-storage")].mountPath' + value: "/mnt/shared" + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-home-storage")].subPath' + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-home-storage")].persistentVolumeClaim.claimName' + value: "RELEASE-NAME-rstudio-workbench-home-storage" + - it: should specify a volumeMount and a volume for homeStorage if homeStorage.mount is true + template: deployment.yaml + set: + homeStorage: + mount: true + path: "/mnt/shared" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-home-storage")].mountPath' + value: "/mnt/shared" + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-home-storage")].subPath' + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-home-storage")].persistentVolumeClaim.claimName' + value: "RELEASE-NAME-rstudio-workbench-home-storage" + - it: should specify a volumeMount and a volume for homeStorage if homeStorage.create is true + template: deployment.yaml + set: + homeStorage: + create: true + path: "/mnt/shared" + subPath: "subpath" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-home-storage")].mountPath' + value: "/mnt/shared" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-home-storage")].subPath' + value: "subpath" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-home-storage")].persistentVolumeClaim.claimName' + value: "RELEASE-NAME-rstudio-workbench-home-storage" + - it: should specify a volumeMount and a volume for homeStorage if homeStorage.mount is true + template: deployment.yaml + set: + homeStorage: + mount: true + path: "/mnt/shared" + subPath: "subpath" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-home-storage")].mountPath' + value: "/mnt/shared" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-home-storage")].subPath' + value: "subpath" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-home-storage")].persistentVolumeClaim.claimName' + value: "RELEASE-NAME-rstudio-workbench-home-storage" + - it: should specify a volumeMount and a volume for the session secret if config.sessionSecret is defined and not empty + template: deployment.yaml + set: + config: + defaultMode: + sessionSecret: 0420 + sessionSecret: + odbc.ini: + dsn: "test" + driver: "test" + session: + defaultSecretMountPath: "/mnt/session-secret" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-session-secret")].mountPath' + value: "/mnt/session-secret" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-session-secret")].name' + value: "rstudio-session-secret" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-session-secret")].name' + value: "rstudio-session-secret" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-session-secret")].secret.secretName' + value: "RELEASE-NAME-rstudio-workbench-session-secret" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-session-secret")].secret.defaultMode' + value: 0420 + - it: should not specify a volumeMount and a volume for the session secret if config.sessionSecret is not defined + template: deployment.yaml + asserts: + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-session-secret")]' + - notExists: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-session-secret")]' + - it: should specify a volumeMount and a volume for userProvisioning if config.userProvisioning is defined and not empty + template: deployment.yaml + set: + config: + defaultMode: + userProvisioning: 0600 + userProvisioning: + sssd.conf: + dsn: "test" + driver: "test" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-user")].mountPath' + value: "/etc/sssd/conf.d/" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-user")].name' + value: "rstudio-user" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-user")].name' + value: "rstudio-user" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-user")].secret.secretName' + value: "RELEASE-NAME-rstudio-workbench-user" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-user")].secret.defaultMode' + value: 0600 + - it: should not specify a volumeMount and a volume for userProvisioning if config.userProvisioning is not defined + template: deployment.yaml + asserts: + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-user")]' + - notExists: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-user")]' + - it: should specify a volumeMount and a volume for launcher if launcher.enabled is true + template: deployment.yaml + set: + config: + defaultMode: + launcher: 0755 + launcher: + enabled: true + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-launcher-startup")].mountPath' + value: "/startup/launcher" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-launcher-startup")].configMap.name' + value: "RELEASE-NAME-rstudio-workbench-start-launcher" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-launcher-startup")].configMap.defaultMode' + value: 0755 + - it: should not specify a volumeMount and a volume for launcher if launcher.enabled is false + template: deployment.yaml + set: + launcher: + enabled: false + asserts: + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-launcher-startup")]' + - notExists: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-launcher-startup")]' + - it: should specify a volumeMount and a volume for startupUserProvisioning if config.startupUserProvisioning is defined and not empty + template: deployment.yaml + set: + config: + defaultMode: + startup: 0600 + startupUserProvisioning: + sssd.conf: + dsn: "test" + driver: "test" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-user-startup")].mountPath' + value: "/startup/user-provisioning" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-user-startup")].name' + value: "rstudio-user-startup" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-user-startup")].name' + value: "rstudio-user-startup" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-user-startup")].configMap.name' + value: "RELEASE-NAME-rstudio-workbench-start-user" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-user-startup")].configMap.defaultMode' + value: 0600 + - it: should not specify a volumeMount and a volume for startupUserProvisioning if config.startupUserProvisioning is not defined + template: deployment.yaml + set: + config: + defaultMode: + startup: 0600 + startupUserProvisioning: null + asserts: + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-user-startup")]' + - notExists: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-user-startup")]' + - it: should specify a volumeMount and a volume for startupCustom if config.startupCustom is defined and not empty + template: deployment.yaml + set: + config: + defaultMode: + startup: 0600 + startupCustom: + sssd.conf: + dsn: "test" + driver: "test" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-custom-startup")].mountPath' + value: "/startup/custom" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-custom-startup")].name' + value: "rstudio-custom-startup" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-custom-startup")].name' + value: "rstudio-custom-startup" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-custom-startup")].configMap.name' + value: "RELEASE-NAME-rstudio-workbench-start-custom" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-custom-startup")].configMap.defaultMode' + value: 0600 + - it: should not specify a volumeMount and a volume for startupCustom if config.startupCustom is not defined + template: deployment.yaml + set: + config: + defaultMode: + startup: 0600 + startupCustom: null + asserts: + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-custom-startup")]' + - notExists: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-custom-startup")]' + - it: should specify a volumeMount and a volume for pam if config.pam is defined and not empty + template: deployment.yaml + set: + config: + defaultMode: + pam: 0600 + pam: + thing.conf: + dsn: "test" + driver: "test" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-pam")].mountPath' + value: "/etc/pam.d/thing.conf" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-pam")].name' + value: "rstudio-pam" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-pam")].subPath' + value: "thing.conf" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-pam")].name' + value: "rstudio-pam" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-pam")].configMap.name' + value: "RELEASE-NAME-rstudio-workbench-pam" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-pam")].configMap.defaultMode' + value: 0600 + - it: should not specify a volumeMount and a volume for pam if config.pam is not defined + template: deployment.yaml + set: + config: + defaultMode: + pam: 0600 + pam: null + asserts: + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-pam")]' + - notExists: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-pam")]' + - it: should specify a volumeMount and a volume for the old style jobJsonOverridesFiles if jobJsonOverridesFiles is defined and not empty + template: deployment.yaml + set: + config: + defaultMode: + jobJsonOverrides: 0644 + jobJsonOverridesFiles: + - name: "test" + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-job-overrides-old")].mountPath' + value: "/mnt/job-json-overrides" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-job-overrides-old")].name' + value: "rstudio-job-overrides-old" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-job-overrides-old")].name' + value: "rstudio-job-overrides-old" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-job-overrides-old")].configMap.name' + value: "RELEASE-NAME-rstudio-workbench-overrides-old" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-job-overrides-old")].configMap.defaultMode' + value: 0644 + - it: should not specify a volumeMount and a volume for the old style jobJsonOverridesFiles if jobJsonOverridesFiles is not defined + template: deployment.yaml + set: + config: + defaultMode: + jobJsonOverrides: 0644 + jobJsonOverridesFiles: {} + asserts: + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-job-overrides-old")]' + - notExists: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-job-overrides-old")]' + +# $useNewOverrides is defined as {- $useNewerOverrides := and (not (hasKey .Values.config.server "launcher.kubernetes.profiles.conf")) (not .Values.launcher.useTemplates) }} + - it: should specify a volumeMount and a volume for the new style jobJsonOverridesFiles if $useNewerOverrides is true + template: deployment.yaml + set: + config: + defaultMode: + jobJsonOverrides: 0644 + launcher: + useTemplates: false + asserts: + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-job-overrides-new")].mountPath' + value: "/mnt/job-json-overrides-new" + - equal: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-job-overrides-new")].name' + value: "rstudio-job-overrides-new" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-job-overrides-new")].name' + value: "rstudio-job-overrides-new" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-job-overrides-new")].configMap.name' + value: "RELEASE-NAME-rstudio-workbench-overrides-new" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-job-overrides-new")].configMap.defaultMode' + value: 0644 + - it: should not specify a volumeMount and a volume for the new style jobJsonOverridesFiles if $useNewerOverrides is false + template: deployment.yaml + set: + config: + server: + launcher.kubernetes.profiles.conf: + thing: "test" + launcher: + useTemplates: true + asserts: + - notExists: + path: 'spec.template.spec.containers[0].volumeMounts[?(@.name=="rstudio-job-overrides-new")]' + - notExists: + path: 'spec.template.spec.volumes[?(@.name=="rstudio-job-overrides-new")]' + - it: should specify 3 volumeMounts and a volume if Values.launcher.useTemplates is true + template: deployment.yaml + set: + config: + defaultMode: + server: 0644 + launcher: + useTemplates: true + asserts: + - contains: + path: 'spec.template.spec.containers[0].volumeMounts' + content: + name: "session-templates" + mountPath: "/var/lib/rstudio-launcher/Kubernetes/rstudio-library-templates-data.tpl" + subPath: "rstudio-library-templates-data.tpl" + any: true + - contains: + path: 'spec.template.spec.containers[0].volumeMounts' + content: + name: "session-templates" + mountPath: "/var/lib/rstudio-launcher/Kubernetes/job.tpl" + subPath: "job.tpl" + any: true + - contains: + path: 'spec.template.spec.containers[0].volumeMounts' + content: + name: "session-templates" + mountPath: "/var/lib/rstudio-launcher/Kubernetes/service.tpl" + subPath: "service.tpl" + any: true + - equal: + path: 'spec.template.spec.volumes[?(@.name=="session-templates")].name' + value: "session-templates" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="session-templates")].configMap.name' + value: "RELEASE-NAME-rstudio-workbench-templates" + - equal: + path: 'spec.template.spec.volumes[?(@.name=="session-templates")].configMap.defaultMode' + value: 0644 + - it: should not specify any volumeMounts or a volume if Values.launcher.useTemplates is false + template: deployment.yaml + set: + launcher: + useTemplates: false + asserts: + - notContains: + path: 'spec.template.spec.containers[0].volumeMounts' + content: + name: "session-templates" + mountPath: "/var/lib/rstudio-launcher/Kubernetes/rstudio-library-templates-data.tpl" + subPath: "rstudio-library-templates-data.tpl" + any: true + - notContains: + path: 'spec.template.spec.containers[0].volumeMounts' + content: + name: "session-templates" + mountPath: "/var/lib/rstudio-launcher/Kubernetes/job.tpl" + subPath: "job.tpl" + any: true + - notContains: + path: 'spec.template.spec.containers[0].volumeMounts' + content: + name: "session-templates" + mountPath: "/var/lib/rstudio-launcher/Kubernetes/service.tpl" + subPath: "service.tpl" + any: true + - notExists: + path: 'spec.template.spec.volumes[?(@.name=="session-templates")]' + - notExists: + path: 'spec.template.spec.volumeMounts[?(@.name=="session-templates")]' + - it: should have the pod volumemounts defined by the user + template: deployment.yaml + set: + pod: + volumeMounts: + - name: "test" + mountPath: "/mnt/test" + - name: "secondTest" + mountPath: "/mnt/secondTest" + asserts: + - contains: + path: 'spec.template.spec.containers[0].volumeMounts' + content: + name: "test" + mountPath: "/mnt/test" + any: true + - contains: + path: 'spec.template.spec.containers[0].volumeMounts' + content: + name: "secondTest" + mountPath: "/mnt/secondTest" + any: true + - it: should set the resource requests if enabled + template: deployment.yaml + set: + resources: + requests: + enabled: true + cpu: "100m" + memory: "128Mi" + asserts: + - equal: + path: 'spec.template.spec.containers[0].resources.requests.cpu' + value: "100m" + - equal: + path: 'spec.template.spec.containers[0].resources.requests.memory' + value: "128Mi" + - notExists: + path: 'spec.template.spec.containers[0].resources.limits' + - it: should set the resource limits if enabled + template: deployment.yaml + set: + resources: + limits: + enabled: true + cpu: "1000m" + memory: "1024Mi" + asserts: + - equal: + path: 'spec.template.spec.containers[0].resources.limits.cpu' + value: "1000m" + - equal: + path: 'spec.template.spec.containers[0].resources.limits.memory' + value: "1024Mi" + - notExists: + path: 'spec.template.spec.containers[0].resources.requests' + - it: should configure the livenessProbe if values.livenessProbe.enabled is true + template: deployment.yaml + set: + livenessProbe: + enabled: true + initialDelaySeconds: 10 + periodSeconds: 20 + asserts: + - equal: + path: 'spec.template.spec.containers[0].livenessProbe.initialDelaySeconds' + value: 10 + - equal: + path: 'spec.template.spec.containers[0].livenessProbe.periodSeconds' + value: 20 + - it: should not configure the livenessProbe if values.livenessProbe.enabled is false + template: deployment.yaml + set: + livenessProbe: + enabled: false + initialDelaySeconds: 10 + periodSeconds: 20 + asserts: + - notExists: + path: 'spec.template.spec.containers[0].livenessProbe' + - it: should configure the startupProbe if values.startupsProbe.enabled is true + template: deployment.yaml + set: + startupProbe: + enabled: true + initialDelaySeconds: 10 + periodSeconds: 20 + asserts: + - equal: + path: 'spec.template.spec.containers[0].startupProbe.initialDelaySeconds' + value: 10 + - equal: + path: 'spec.template.spec.containers[0].startupProbe.periodSeconds' + value: 20 + - it: should not configure the startupProbe if values.startupProbe.enabled is false + template: deployment.yaml + set: + startupProbe: + enabled: false + initialDelaySeconds: 10 + periodSeconds: 20 + asserts: + - notExists: + path: 'spec.template.spec.containers[0].startupProbe' + - it: should configure the readinessProbe if values.readinessProbe.enabled is true + template: deployment.yaml + set: + readinessProbe: + enabled: true + initialDelaySeconds: 10 + periodSeconds: 20 + asserts: + - equal: + path: 'spec.template.spec.containers[0].readinessProbe.initialDelaySeconds' + value: 10 + - equal: + path: 'spec.template.spec.containers[0].readinessProbe.periodSeconds' + value: 20 + - it: should not configure the readinessProbe if values.readinessProbe.enabled is false + template: deployment.yaml + set: + readinessProbe: + enabled: false + initialDelaySeconds: 10 + periodSeconds: 20 + asserts: + - notExists: + path: 'spec.template.spec.containers[0].readinessProbe' + - it: should create a sidecar container if pod.sidecar is defined + template: deployment.yaml + set: + pod: + sidecar: + - name: "sidecarTest" + image: "test" + asserts: + - exists: + path: 'spec.template.spec.containers[?(@.name=="sidecarTest")]' diff --git a/ci/rstudio-workbench/tests/ingress_test.yaml b/ci/rstudio-workbench/tests/ingress_test.yaml new file mode 100644 index 00000000..ad7f878d --- /dev/null +++ b/ci/rstudio-workbench/tests/ingress_test.yaml @@ -0,0 +1,58 @@ +suite: Workbench Ingress +templates: + - ingress.yaml +tests: + - it: should include the tls path if tls has values specified and ingress is enabled + template: ingress.yaml + set: + ingress: + enabled: true + tls: + - hosts: + - "example.com" + secretName: "example-tls" + asserts: + - exists: + path: "spec.tls" + - equal: + path: "spec.tls[0].hosts[0]" + value: "example.com" + - it: should not include the tls path if tls has no values specified and ingress is enabled + template: ingress.yaml + set: + ingress: + enabled: true + tls: [] + asserts: + - notExists: + path: "spec.tls" + - it: should include the tls path if tls has values specified and ingress is enabled + template: ingress.yaml + set: + ingress: + enabled: true + tls: + - secretName: chart-example-tls + hosts: + - chart-example.local + asserts: + - exists: + path: "spec.tls" + - it: should include the ingressClassName if defined and ingress is enabled + template: ingress.yaml + set: + ingress: + enabled: true + ingressClassName: "alb" + asserts: + - equal: + path: "spec.ingressClassName" + value: "alb" + - it: should not include the ingressClassName if it is not defined and ingress is enabled + template: ingress.yaml + set: + ingress: + enabled: true + asserts: + - notExists: + path: "spec.ingressClassName" diff --git a/ci/rstudio-workbench/tests/prometheus_test.yaml b/ci/rstudio-workbench/tests/prometheus_test.yaml new file mode 100644 index 00000000..bb211e67 --- /dev/null +++ b/ci/rstudio-workbench/tests/prometheus_test.yaml @@ -0,0 +1,104 @@ +suite: Workbench prometheus configuration +templates: + - configmap-general.yaml + - configmap-graphite-exporter.yaml + - configmap-prestart.yaml + - configmap-secret.yaml + - configmap-session.yaml + - deployment.yaml + - svc.yaml +tests: + - it: should ensure the specified metrics port is used in the service if prometheus is enabled and legacy is not true + template: svc.yaml + set: + prometheus: + enabled: true + port: 8989 + asserts: + - equal: + path: "spec.ports[1].name" + value: "metrics" + - equal: + path: "spec.ports[1].port" + value: 8989 + - it: should ensure the legacy metrics port is used in the service if prometheus is enabled and legacy is true + template: svc.yaml + set: + prometheus: + enabled: true + legacy: true + port: 8989 + asserts: + - equal: + path: "spec.ports[1].name" + value: "metrics" + - equal: + path: "spec.ports[1].port" + value: 9108 + - it: should ensure the prometheus annotations are defined in the service, and that the graphite exporter checksum is non-existent + template: deployment.yaml + set: + prometheus: + enabled: true + port: 8989 + asserts: + - isSubset: + path: spec.template.metadata.annotations + content: + prometheus.io/scrape: "true" + prometheus.io/path: "/metrics" + prometheus.io/port: "8989" + - notExists: + path: "spec.template.metadata.annotations.checksum/config-graphite" + - it: should ensure the legacy prometheus annotations are defined in the service, and that the graphite exporter checksum exists + template: deployment.yaml + set: + prometheus: + enabled: true + legacy: true + port: 8989 + asserts: + - isSubset: + path: spec.template.metadata.annotations + content: + prometheus.io/scrape: "true" + prometheus.io/path: "/metrics" + prometheus.io/port: "9108" + - exists: + path: "spec.template.metadata.annotations.checksum/config-graphite" + - it: should ensure the legacy metrics port is used and that the graphite exporter container exists + template: deployment.yaml + set: + prometheus: + enabled: true + legacy: true + port: 8989 + prometheusExporter: + enabled: true + asserts: + - equal: + path: "spec.template.spec.containers[1].name" + value: "exporter" + - equal: + path: "spec.template.spec.containers[1].ports[0].name" + value: "metrics" + - equal: + path: "spec.template.spec.containers[1].ports[0].containerPort" + value: 9108 + - it: should ensure the metrics port is used in the rstudio container if prometheus is enabled and legacy is not true + template: deployment.yaml + set: + prometheus: + enabled: true + legacy: false + port: 8989 + asserts: + - equal: + path: "spec.template.spec.containers[0].name" + value: "rstudio" + - equal: + path: "spec.template.spec.containers[0].ports[1].name" + value: "metrics" + - equal: + path: "spec.template.spec.containers[0].ports[1].containerPort" + value: 8989 diff --git a/ci/rstudio-workbench/tests/service_accounts_test.yaml b/ci/rstudio-workbench/tests/service_accounts_test.yaml new file mode 100644 index 00000000..b16a7af5 --- /dev/null +++ b/ci/rstudio-workbench/tests/service_accounts_test.yaml @@ -0,0 +1,63 @@ +suite: Workbench Service Accounts +templates: + - configmap-general.yaml + - configmap-prestart.yaml + - configmap-secret.yaml + - configmap-session.yaml + - deployment.yaml +tests: + - it: should set the Workbench pod service account when the launcher is enabled + template: deployment.yaml + set: + launcher: + enabled: true + rbac: + serviceAccount: + name: "workbench-service-account" + asserts: + - equal: + path: "spec.template.spec.serviceAccountName" + value: "workbench-service-account" + - it: should set the Workbench pod service account when the launcher is not enabled + template: deployment.yaml + set: + launcher: + enabled: false + rbac: + serviceAccount: + name: "workbench-service-account" + asserts: + - equal: + path: "spec.template.spec.serviceAccountName" + value: "workbench-service-account" + - it: should use the default serviceAccount name when not set + template: deployment.yaml + asserts: + - equal: + path: "spec.template.spec.serviceAccountName" + value: "RELEASE-NAME-rstudio-workbench" + - it: should use the nameOverride as part of the serviceAccount name when nameOverride is set + template: deployment.yaml + set: + nameOverride: "posit-workbench" + asserts: + - equal: + path: "spec.template.spec.serviceAccountName" + value: "RELEASE-NAME-posit-workbench" + - it: should use the fullnameOverride as the serviceAccount name when fullnameOverride is set + template: deployment.yaml + set: + fullnameOverride: "posit-workbench" + asserts: + - equal: + path: "spec.template.spec.serviceAccountName" + value: "posit-workbench" + - it: should use the fullnameOverride as the serviceAccount name when fullnameOverride is set even if nameOverride is set + template: deployment.yaml + set: + fullnameOverride: "posit-workbench" + nameOverride: "old-workbench" + asserts: + - equal: + path: "spec.template.spec.serviceAccountName" + value: "posit-workbench" diff --git a/examples/connect/application-configuration/index.qmd b/examples/connect/application-configuration/index.qmd index 2ceb80c6..c8475c97 100644 --- a/examples/connect/application-configuration/index.qmd +++ b/examples/connect/application-configuration/index.qmd @@ -1,5 +1,5 @@ --- -category: "Basic Configuration" +category: "Basic configuration" --- # Configuring Posit Connect with Recommended Settings diff --git a/examples/connect/beta-migration/index.qmd b/examples/connect/beta-migration/index.qmd index 2993a3eb..99e81200 100644 --- a/examples/connect/beta-migration/index.qmd +++ b/examples/connect/beta-migration/index.qmd @@ -1,5 +1,5 @@ --- -category: "Beta Migration" +category: "Beta migration" --- # Off-Host Execution Beta User Migration diff --git a/examples/connect/container-images/custom-images.qmd b/examples/connect/container-images/custom-images.qmd index 5407c999..0b73badc 100644 --- a/examples/connect/container-images/custom-images.qmd +++ b/examples/connect/container-images/custom-images.qmd @@ -1,5 +1,5 @@ --- -category: "Container Images" +category: "Container images" --- # Configuring Posit Connect with Custom Container Images diff --git a/examples/connect/container-images/private-images.qmd b/examples/connect/container-images/private-images.qmd index 6d387753..cfad496b 100644 --- a/examples/connect/container-images/private-images.qmd +++ b/examples/connect/container-images/private-images.qmd @@ -1,5 +1,5 @@ --- -category: "Container Images" +category: "Container images" --- # Configuring Posit Connect to Access Image Registries Requiring Authentication diff --git a/examples/examples.ejs b/examples/examples.ejs index 069909a4..4fdf632f 100644 --- a/examples/examples.ejs +++ b/examples/examples.ejs @@ -2,7 +2,7 @@ const postsByCategory = {}; const basicConfigPosts = []; items.forEach(item => { - if (item.category === "Basic Configuration") { + if (item.category === "Basic configuration") { basicConfigPosts.push(item) } else { if (!postsByCategory[item.category]) { @@ -14,7 +14,7 @@ items.forEach(item => { // Basic config first if (basicConfigPosts.length > 0) { %> -

Basic Configuration

+

Basic configuration

    <% basicConfigPosts.forEach(post => { %>
  • diff --git a/examples/launcher-templates/default/2.4.0/job.tpl b/examples/launcher-templates/default/2.4.0/job.tpl new file mode 100644 index 00000000..9f7350d1 --- /dev/null +++ b/examples/launcher-templates/default/2.4.0/job.tpl @@ -0,0 +1,219 @@ +# Version: 2.4.0 +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + {{- with .Job.metadata.job.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + labels: + app.kubernetes.io/managed-by: "launcher" + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} + {{- with .Job.metadata.job.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + generateName: {{ toYaml .Job.generateName }} +spec: + backoffLimit: 0 + template: + metadata: + annotations: + {{- if .Job.tags }} + {{- $i := 0 }} + {{- range .Job.tags }} + USER_TAG_{{ $i }}: {{ toYaml . | indent 8 | trimPrefix (repeat 8 " ") }} + {{- $i = add $i 1 }} + {{- end }} + {{- end }} + stdin: {{ toYaml .Job.stdin | indent 8 | trimPrefix (repeat 8 " ") }} + user: {{ toYaml .Job.user }} + name: {{ toYaml .Job.name }} + service_ports: {{ toYaml .Job.servicePortsJson }} + {{- if .Job.metadata }} + user_metadata: {{ toJson .Job.metadata | toYaml | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- with .Job.metadata.pod.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + labels: + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} + {{- with .Job.metadata.pod.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + generateName: {{ toYaml .Job.generateName }} + spec: + {{- if .Job.host }} + nodeName: {{ toYaml .Job.host }} + {{- end }} + restartPolicy: Never + shareProcessNamespace: {{ .Job.shareProcessNamespace }} + {{- if ne (len .Job.volumes) 0 }} + volumes: + {{- range .Job.volumes }} + - {{ nindent 10 (toYaml .) | trim -}} + {{- end }} + {{- end }} + {{- if ne (len .Job.placementConstraints) 0 }} + nodeSelector: + {{- range .Job.placementConstraints }} + {{ .name }}: {{ toYaml .value }} + {{- end }} + {{- end }} + {{- $securityContext := dict }} + {{- if .Job.container.runAsUserId }} + {{- $_ := set $securityContext "runAsUser" .Job.container.runAsUserId }} + {{- end }} + {{- if .Job.container.runAsGroupId }} + {{- $_ := set $securityContext "runAsGroup" .Job.container.runAsGroupId }} + {{- end }} + {{- if .Job.container.supplementalGroupIds }} + {{- $groupIds := list }} + {{- range .Job.container.supplementalGroupIds }} + {{- $groupIds = append $groupIds . }} + {{- end }} + {{- $_ := set $securityContext "supplementalGroups" (cat "[" ($groupIds | join ", ") "]") }} + {{- end }} + {{- if $securityContext }} + securityContext: + {{- range $key, $val := $securityContext }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- if .Job.serviceAccountName }} + serviceAccountName: {{ .Job.serviceAccountName | quote }} + {{- end }} + initContainers: + {{- with .Job.metadata.pod.initContainers }} + {{- range . }} + - {{ toYaml . | indent 10 | trimPrefix (repeat 10 " ") }} + {{- end }} + {{- end }} + containers: + - name: rs-launcher-container + image: {{ toYaml .Job.container.image }} + {{- $isShell := false }} + {{- if .Job.command }} + command: ['/bin/sh'] + {{- $isShell = true }} + {{- else }} + command: [{{ toYaml .Job.exe }}] + {{- $isShell = false }} + {{- end }} + {{- if .Job.stdin }} + stdin: true + {{- else }} + stdin: false + {{- end }} + stdinOnce: true + {{- if .Job.workingDirectory }} + workingDir: {{ toYaml .Job.workingDirectory }} + {{- end }} + {{- if or (ne (len .Job.args) 0) $isShell }} + args: + {{- if $isShell }} + - '-c' + {{- if ne (len .Job.args) 0 }} + - {{ .Job.args | join " " | cat .Job.command | toYaml | indent 12 | trimPrefix (repeat 12 " ") }} + {{- else }} + - {{ .Job.command | toYaml | indent 12 | trimPrefix (repeat 12 " ") }} + {{- end }} + {{- else }} + {{- range .Job.args }} + - {{ toYaml . | indent 12 | trimPrefix (repeat 12 " ") }} + {{- end }} + {{- end }} + {{- end }} + {{- $secrets := list }} + {{- range .Job.config }} + {{- if eq .name "secret" }} + {{- $packedSecret := .value }} + {{- $secret := dict }} + {{- $_ := set $secret "secret" (splitList ":" $packedSecret | first) }} + {{- $_ := set $secret "key" (slice (splitList ":" $packedSecret) 1 2 | first) }} + {{- $_ := set $secret "name" (splitList ":" $packedSecret | last) }} + {{- $secrets = append $secrets $secret }} + {{- end }} + {{- end }} + {{- if or (ne (len .Job.environment) 0) (ne (len $secrets) 0) }} + env: + {{- range .Job.environment }} + - name: {{ toYaml .name | indent 14 | trimPrefix (repeat 14 " ") }} + value: {{ toYaml .value | indent 14 | trimPrefix (repeat 14 " ") }} + {{- end }} + {{- range $secrets }} + - name: {{ get . "name"}} + valueFrom: + secretKeyRef: + name: {{ get . "secret" }} + key: {{ get . "key" }} + {{- end }} + {{- end }} + {{- $exposedPorts := list }} + {{- range .Job.exposedPorts }} + {{- if .publishedPort }} + {{- $exposedPorts = append $exposedPorts . }} + {{- end }} + {{- end }} + {{- if ne (len $exposedPorts) 0 }} + ports: + {{- range $exposedPorts }} + - containerPort: {{ .targetPort }} + hostPort: {{ .publishedPort }} + {{- end }} + {{- end }} + {{- $limits := dict }} + {{- $requests := dict }} + {{- range .Job.resourceLimits }} + {{- if eq .type "cpuCount" }} + {{- $_ := set $limits "cpu" .value }} + {{- else if eq .type "CPU Request" }} + {{- $_ := set $requests "cpu" .value }} + {{- else if eq .type "memory" }} + {{- $_ := set $limits "memory" (printf "%s%s" .value "M") }} + {{- else if eq .type "Memory Request" }} + {{- $_ := set $requests "memory" (printf "%s%s" .value "M") }} + {{- else if eq .type "NVIDIA GPUs" }} + {{- $val := float64 .value }} + {{- if ne $val 0.0 }} + {{- $_ := set $limits "nvidia.com/gpu" $val }} + {{- end }} + {{- else if eq .type "AMD GPUs" }} + {{- $val := float64 .value }} + {{- if ne $val 0.0 }} + {{- $_ := set $limits "amd.com/gpu" $val }} + {{- end }} + {{- end }} + {{- end }} + {{- if any (ne (len $requests) 0) (ne (len $limits) 0) }} + resources: + {{- if ne (len $requests) 0 }} + requests: + {{- range $key, $val := $requests }} + {{ $key }}: {{ toYaml $val }} + {{- end }} + {{- end }} + {{- if ne (len $limits) 0 }} + limits: + {{- range $key, $val := $limits }} + {{ $key }}: {{ toYaml $val }} + {{- end }} + {{- end }} + {{- end }} + {{- if ne (len .Job.volumes) 0 }} + volumeMounts: + {{- range .Job.volumeMounts }} + - {{ nindent 14 (toYaml .) | trim -}} + {{- end }} + {{- end }} diff --git a/examples/launcher-templates/default/2.4.0/service.tpl b/examples/launcher-templates/default/2.4.0/service.tpl new file mode 100644 index 00000000..8b851c1c --- /dev/null +++ b/examples/launcher-templates/default/2.4.0/service.tpl @@ -0,0 +1,38 @@ +# Version: 2.4.0 +apiVersion: v1 +kind: Service +metadata: + name: {{ .Job.serviceName }} + annotations: + {{- with .Job.metadata.service.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + labels: + app.kubernetes.io/managed-by: "launcher" + job-name: {{ toYaml .Job.id }} + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} + {{- with .Job.metadata.service.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} +spec: + ports: + {{- $i := 0 }} + {{- range .Job.exposedPorts }} + {{- if not .publishedPort }} + - name: {{ printf "port%d" $i }} + protocol: {{ .protocol }} + port: {{ .targetPort }} + targetPort: {{ .targetPort }} + {{- $i = add $i 1 }} + {{- end }} + {{- end }} + selector: + job-name: {{toYaml .Job.id }} + clusterIP: '' + type: NodePort diff --git a/examples/launcher-templates/helm/2.4.0-v1/job.tpl b/examples/launcher-templates/helm/2.4.0-v1/job.tpl new file mode 100644 index 00000000..a0101a8d --- /dev/null +++ b/examples/launcher-templates/helm/2.4.0-v1/job.tpl @@ -0,0 +1,292 @@ +# Version: 2.4.0 +# DO NOT MODIFY the "Version: " key +# Helm Version: v1 +{{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + {{- with .Job.metadata.job.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.job.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + labels: + app.kubernetes.io/managed-by: "launcher" + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} + {{- with .Job.metadata.job.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.job.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + generateName: {{ toYaml .Job.generateName }} +spec: + {{- if $templateData.job.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ $templateData.job.ttlSecondsAfterFinished }} + {{- end }} + backoffLimit: 0 + template: + metadata: + annotations: + {{- if .Job.tags }} + {{- $i := 0 }} + {{- range .Job.tags }} + USER_TAG_{{ $i }}: {{ toYaml . | indent 8 | trimPrefix (repeat 8 " ") }} + {{- $i = add $i 1 }} + {{- end }} + {{- end }} + stdin: {{ toYaml .Job.stdin | indent 8 | trimPrefix (repeat 8 " ") }} + user: {{ toYaml .Job.user }} + name: {{ toYaml .Job.name }} + service_ports: {{ toYaml .Job.servicePortsJson }} + {{- if .Job.metadata }} + user_metadata: {{ toJson .Job.metadata | toYaml | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- with .Job.metadata.pod.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.pod.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + labels: + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} + {{- with .Job.metadata.pod.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.pod.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + generateName: {{ toYaml .Job.generateName }} + spec: + {{- if .Job.host }} + nodeName: {{ toYaml .Job.host }} + {{- end }} + enableServiceLinks: {{ if hasKey $templateData.pod "enableServiceLinks" }}{{ $templateData.pod.enableServiceLinks }}{{ else }}false{{ end }} + restartPolicy: Never + {{- if or $templateData.pod.serviceAccountName .Job.serviceAccountName }} + serviceAccountName: {{ .Job.serviceAccountName | default $templateData.pod.serviceAccountName | quote }} + {{- end }} + shareProcessNamespace: {{ .Job.shareProcessNamespace }} + {{- if or (ne (len .Job.volumes) 0) (ne (len $templateData.pod.volumes) 0) }} + volumes: + {{- range .Job.volumes }} + - {{ nindent 10 (toYaml .) | trim -}} + {{- end }} + {{- range $templateData.pod.volumes }} + - {{ nindent 10 (toYaml .) | trim -}} + {{- end }} + {{- end }} + {{- with $templateData.pod.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $templateData.pod.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or (ne (len .Job.placementConstraints) 0) (and $templateData.pod.nodeSelector (ne (len $templateData.pod.nodeSelector) 0)) }} + nodeSelector: + {{- range .Job.placementConstraints }} + {{ .name }}: {{ toYaml .value }} + {{- end }} + {{- range $key,$val := $templateData.pod.nodeSelector }} + {{ $key }}: {{- toYaml $val | nindent 10 }} + {{- end }} + {{- end }} + {{- with $templateData.pod.priorityClassName }} + priorityClassName: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- $securityContext := $templateData.pod.defaultSecurityContext }} + {{- if .Job.container.runAsUserId }} + {{- $_ := set $securityContext "runAsUser" .Job.container.runAsUserId }} + {{- end }} + {{- if .Job.container.runAsGroupId }} + {{- $_ := set $securityContext "runAsGroup" .Job.container.runAsGroupId }} + {{- end }} + {{- if .Job.container.supplementalGroupIds }} + {{- $groupIds := list }} + {{- range .Job.container.supplementalGroupIds }} + {{- $groupIds = append $groupIds . }} + {{- end }} + {{- $_ := set $securityContext "supplementalGroups" (cat "[" ($groupIds | join ", ") "]") }} + {{- $securityContext := mergeOverwrite $securityContext $templateData.pod.securityContext }} + {{- end }} + {{- if $securityContext }} + securityContext: + {{- range $key, $val := $securityContext }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- with $templateData.pod.imagePullSecrets }} + imagePullSecrets: {{ toYaml . | nindent 12 }} + {{- end }} + initContainers: + {{- with .Job.metadata.pod.initContainers }} + {{- range . }} + - {{ toYaml . | indent 10 | trimPrefix (repeat 10 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.pod.initContainers }} + {{- range . }} + - {{ toYaml . | indent 10 | trimPrefix (repeat 10 " ") }} + {{- end }} + {{- end }} + containers: + - name: rs-launcher-container + image: {{ toYaml .Job.container.image }} + {{- with $templateData.pod.imagePullPolicy }} + imagePullPolicy: {{- . | nindent 12 }} + {{- end }} + {{- $isShell := false }} + {{- if $templateData.pod.command }} + command: {{- toYaml $templateData.pod.command | nindent 12 }} + {{- if .Job.command }}{{- $isShell = true }}{{- end }} + {{- else if .Job.command }} + command: ['/bin/sh'] + {{- $isShell = true }} + {{- else }} + command: [{{ toYaml .Job.exe }}] + {{- $isShell = false }} + {{- end }} + {{- if .Job.stdin }} + stdin: true + {{- else }} + stdin: false + {{- end }} + stdinOnce: true + {{- if .Job.workingDirectory }} + workingDir: {{ toYaml .Job.workingDirectory }} + {{- end }} + {{- if or (ne (len .Job.args) 0) $isShell }} + args: + {{- if $isShell }} + - '-c' + {{- if ne (len .Job.args) 0 }} + - {{ .Job.args | join " " | cat .Job.command | toYaml | indent 12 | trimPrefix (repeat 12 " ") }} + {{- else }} + - {{ .Job.command | toYaml | indent 12 | trimPrefix (repeat 12 " ") }} + {{- end }} + {{- else }} + {{- range .Job.args }} + - {{ toYaml . | indent 12 | trimPrefix (repeat 12 " ") }} + {{- end }} + {{- end }} + {{- end }} + {{- $secrets := list }} + {{- range .Job.config }} + {{- if eq .name "secret" }} + {{- $packedSecret := .value }} + {{- $secret := dict }} + {{- $_ := set $secret "secret" (splitList ":" $packedSecret | first) }} + {{- $_ := set $secret "key" (slice (splitList ":" $packedSecret) 1 2 | first) }} + {{- $_ := set $secret "name" (splitList ":" $packedSecret | last) }} + {{- $secrets = append $secrets $secret }} + {{- end }} + {{- end }} + {{- if or (ne (len .Job.environment) 0) (ne (len $secrets) 0) (ne (len $templateData.pod.env) 0) }} + env: + {{- range .Job.environment }} + - name: {{ toYaml .name | indent 14 | trimPrefix (repeat 14 " ") }} + value: {{ toYaml .value | indent 14 | trimPrefix (repeat 14 " ") }} + {{- end }} + {{- range $secrets }} + - name: {{ get . "name"}} + valueFrom: + secretKeyRef: + name: {{ get . "secret" }} + key: {{ get . "key" }} + {{- end }} + {{- if $templateData.pod.env }} + {{- toYaml $templateData.pod.env | nindent 12 }} + {{- end }} + {{- end }} + {{- with $templateData.pod.containerSecurityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- $exposedPorts := list }} + {{- range .Job.exposedPorts }} + {{- if .publishedPort }} + {{- $exposedPorts = append $exposedPorts . }} + {{- end }} + {{- end }} + {{- if ne (len $exposedPorts) 0 }} + ports: + {{- range $exposedPorts }} + - containerPort: {{ .targetPort }} + hostPort: {{ .publishedPort }} + {{- end }} + {{- end }} + {{- $limits := dict }} + {{- $requests := dict }} + {{- range .Job.resourceLimits }} + {{- if eq .type "cpuCount" }} + {{- $_ := set $limits "cpu" .value }} + {{- else if eq .type "CPU Request" }} + {{- $_ := set $requests "cpu" .value }} + {{- else if eq .type "memory" }} + {{- $_ := set $limits "memory" (printf "%s%s" .value "M") }} + {{- else if eq .type "Memory Request" }} + {{- $_ := set $requests "memory" (printf "%s%s" .value "M") }} + {{- else if eq .type "NVIDIA GPUs" }} + {{- $val := float64 .value }} + {{- if ne $val 0.0 }} + {{- $_ := set $limits "nvidia.com/gpu" $val }} + {{- end }} + {{- else if eq .type "AMD GPUs" }} + {{- $val := float64 .value }} + {{- if ne $val 0.0 }} + {{- $_ := set $limits "amd.com/gpu" $val }} + {{- end }} + {{- end }} + {{- end }} + {{- if any (ne (len $requests) 0) (ne (len $limits) 0) }} + resources: + {{- if ne (len $requests) 0 }} + requests: + {{- range $key, $val := $requests }} + {{ $key }}: {{ toYaml $val }} + {{- end }} + {{- end }} + {{- if ne (len $limits) 0 }} + limits: + {{- range $key, $val := $limits }} + {{ $key }}: {{ toYaml $val }} + {{- end }} + {{- end }} + {{- end }} + {{- if or (ne (len .Job.volumes) 0) (ne (len $templateData.pod.volumeMounts) 0) }} + volumeMounts: + {{- range .Job.volumeMounts }} + - {{ nindent 14 (toYaml .) | trim -}} + {{- end }} + {{- range $templateData.pod.volumeMounts }} + - {{ nindent 14 (toYaml .) | trim -}} + {{- end }} + {{- end }} + {{- with $templateData.pod.extraContainers }} + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/examples/launcher-templates/helm/2.4.0-v1/service.tpl b/examples/launcher-templates/helm/2.4.0-v1/service.tpl new file mode 100644 index 00000000..30bfca27 --- /dev/null +++ b/examples/launcher-templates/helm/2.4.0-v1/service.tpl @@ -0,0 +1,51 @@ +# Version: 2.4.0 +# DO NOT MODIFY the "Version: " key +# Helm Version: v1 +{{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Job.serviceName }} + annotations: + {{- with .Job.metadata.service.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.service.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + labels: + app.kubernetes.io/managed-by: "launcher" + job-name: {{ toYaml .Job.id }} + {{- with .Job.instanceId }} + launcher-instance-id: {{ toYaml . }} + {{- end }} + {{- with .Job.metadata.service.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.service.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} +spec: + ports: + {{- $i := 0 }} + {{- range .Job.exposedPorts }} + {{- if not .publishedPort }} + - name: {{ printf "port%d" $i }} + protocol: {{ .protocol }} + port: {{ .targetPort }} + targetPort: {{ .targetPort }} + {{- $i = add $i 1 }} + {{- end }} + {{- end }} + selector: + job-name: {{toYaml .Job.id }} + clusterIP: '' + type: {{ $templateData.service.type }} diff --git a/examples/package-manager/container-images/custom-images.qmd b/examples/package-manager/container-images/custom-images.qmd index ef765035..b8fbb38d 100644 --- a/examples/package-manager/container-images/custom-images.qmd +++ b/examples/package-manager/container-images/custom-images.qmd @@ -1,5 +1,5 @@ --- -category: "Container Images" +category: "Container images" --- # Configuring Posit Package Manager with Custom Container Images diff --git a/examples/package-manager/container-images/private-images.qmd b/examples/package-manager/container-images/private-images.qmd index 5f9dd663..112614eb 100644 --- a/examples/package-manager/container-images/private-images.qmd +++ b/examples/package-manager/container-images/private-images.qmd @@ -1,5 +1,5 @@ --- -category: "Container Images" +category: "Container images" --- # Configuring Posit Package Manager to Access Image Registries Requiring Authentication diff --git a/examples/rbac/rstudio-launcher-rbac-0.2.21.yaml b/examples/rbac/rstudio-launcher-rbac-0.2.21.yaml new file mode 100644 index 00000000..3b322f8d --- /dev/null +++ b/examples/rbac/rstudio-launcher-rbac-0.2.21.yaml @@ -0,0 +1,88 @@ +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: rstudio-launcher-rbac +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: rstudio-launcher-rbac +rules: + - apiGroups: + - "" + resources: + - "serviceaccounts" + verbs: + - "list" + - apiGroups: + - "" + resources: + - "pods/log" + verbs: + - "get" + - "watch" + - "list" + - apiGroups: + - "" + resources: + - "pods" + - "pods/attach" + - "pods/exec" + verbs: + - "get" + - "create" + - "update" + - "patch" + - "watch" + - "list" + - "delete" + - apiGroups: + - "" + resources: + - "events" + verbs: + - "watch" + - apiGroups: + - "" + resources: + - "services" + verbs: + - "create" + - "get" + - "watch" + - "list" + - "delete" + - apiGroups: + - "batch" + resources: + - "jobs" + verbs: + - "create" + - "update" + - "patch" + - "get" + - "watch" + - "list" + - "delete" + - apiGroups: + - "metrics.k8s.io" + resources: + - "pods" + verbs: + - "get" +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rstudio-launcher-rbac +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rstudio-launcher-rbac +subjects: + - kind: ServiceAccount + name: rstudio-launcher-rbac diff --git a/examples/rbac/rstudio-launcher-rbac-0.2.22.yaml b/examples/rbac/rstudio-launcher-rbac-0.2.22.yaml new file mode 100644 index 00000000..3b322f8d --- /dev/null +++ b/examples/rbac/rstudio-launcher-rbac-0.2.22.yaml @@ -0,0 +1,88 @@ +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: rstudio-launcher-rbac +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: rstudio-launcher-rbac +rules: + - apiGroups: + - "" + resources: + - "serviceaccounts" + verbs: + - "list" + - apiGroups: + - "" + resources: + - "pods/log" + verbs: + - "get" + - "watch" + - "list" + - apiGroups: + - "" + resources: + - "pods" + - "pods/attach" + - "pods/exec" + verbs: + - "get" + - "create" + - "update" + - "patch" + - "watch" + - "list" + - "delete" + - apiGroups: + - "" + resources: + - "events" + verbs: + - "watch" + - apiGroups: + - "" + resources: + - "services" + verbs: + - "create" + - "get" + - "watch" + - "list" + - "delete" + - apiGroups: + - "batch" + resources: + - "jobs" + verbs: + - "create" + - "update" + - "patch" + - "get" + - "watch" + - "list" + - "delete" + - apiGroups: + - "metrics.k8s.io" + resources: + - "pods" + verbs: + - "get" +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rstudio-launcher-rbac +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rstudio-launcher-rbac +subjects: + - kind: ServiceAccount + name: rstudio-launcher-rbac diff --git a/examples/rbac/rstudio-launcher-rbac-0.2.23.yaml b/examples/rbac/rstudio-launcher-rbac-0.2.23.yaml new file mode 100644 index 00000000..3b322f8d --- /dev/null +++ b/examples/rbac/rstudio-launcher-rbac-0.2.23.yaml @@ -0,0 +1,88 @@ +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: rstudio-launcher-rbac +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: rstudio-launcher-rbac +rules: + - apiGroups: + - "" + resources: + - "serviceaccounts" + verbs: + - "list" + - apiGroups: + - "" + resources: + - "pods/log" + verbs: + - "get" + - "watch" + - "list" + - apiGroups: + - "" + resources: + - "pods" + - "pods/attach" + - "pods/exec" + verbs: + - "get" + - "create" + - "update" + - "patch" + - "watch" + - "list" + - "delete" + - apiGroups: + - "" + resources: + - "events" + verbs: + - "watch" + - apiGroups: + - "" + resources: + - "services" + verbs: + - "create" + - "get" + - "watch" + - "list" + - "delete" + - apiGroups: + - "batch" + resources: + - "jobs" + verbs: + - "create" + - "update" + - "patch" + - "get" + - "watch" + - "list" + - "delete" + - apiGroups: + - "metrics.k8s.io" + resources: + - "pods" + verbs: + - "get" +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rstudio-launcher-rbac +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rstudio-launcher-rbac +subjects: + - kind: ServiceAccount + name: rstudio-launcher-rbac diff --git a/examples/rbac/rstudio-launcher-rbac-0.2.24.yaml b/examples/rbac/rstudio-launcher-rbac-0.2.24.yaml new file mode 100644 index 00000000..3b322f8d --- /dev/null +++ b/examples/rbac/rstudio-launcher-rbac-0.2.24.yaml @@ -0,0 +1,88 @@ +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: rstudio-launcher-rbac +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: rstudio-launcher-rbac +rules: + - apiGroups: + - "" + resources: + - "serviceaccounts" + verbs: + - "list" + - apiGroups: + - "" + resources: + - "pods/log" + verbs: + - "get" + - "watch" + - "list" + - apiGroups: + - "" + resources: + - "pods" + - "pods/attach" + - "pods/exec" + verbs: + - "get" + - "create" + - "update" + - "patch" + - "watch" + - "list" + - "delete" + - apiGroups: + - "" + resources: + - "events" + verbs: + - "watch" + - apiGroups: + - "" + resources: + - "services" + verbs: + - "create" + - "get" + - "watch" + - "list" + - "delete" + - apiGroups: + - "batch" + resources: + - "jobs" + verbs: + - "create" + - "update" + - "patch" + - "get" + - "watch" + - "list" + - "delete" + - apiGroups: + - "metrics.k8s.io" + resources: + - "pods" + verbs: + - "get" +--- +# Source: rstudio-launcher-rbac/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: rstudio-launcher-rbac +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rstudio-launcher-rbac +subjects: + - kind: ServiceAccount + name: rstudio-launcher-rbac diff --git a/examples/workbench/application-configuration/index.qmd b/examples/workbench/application-configuration/index.qmd index 298a98ca..4551a908 100644 --- a/examples/workbench/application-configuration/index.qmd +++ b/examples/workbench/application-configuration/index.qmd @@ -1,5 +1,5 @@ --- -category: "Basic Configuration" +category: "Basic configuration" --- # Configuring Posit Workbench with Recommended Settings diff --git a/examples/workbench/container-images/custom-images.qmd b/examples/workbench/container-images/custom-images.qmd index df55c281..10ec1dab 100644 --- a/examples/workbench/container-images/custom-images.qmd +++ b/examples/workbench/container-images/custom-images.qmd @@ -1,5 +1,5 @@ --- -category: "Container Images" +category: "Container images" --- # Configuring Posit Workbench with Custom Container Images diff --git a/examples/workbench/container-images/private-images.qmd b/examples/workbench/container-images/private-images.qmd index 886c926e..8a74b6cf 100644 --- a/examples/workbench/container-images/private-images.qmd +++ b/examples/workbench/container-images/private-images.qmd @@ -1,5 +1,5 @@ --- -category: "Container Images" +category: "Container images" --- # Configuring Posit Workbench to Access Image Registries Requiring Authentication diff --git a/examples/workbench/index.qmd b/examples/workbench/index.qmd index 6b6ec2c0..2a3fb88a 100644 --- a/examples/workbench/index.qmd +++ b/examples/workbench/index.qmd @@ -12,7 +12,7 @@ Before using an example, read through all the comments and ensure you address ea While each example focuses on one or more particular configurations, RStudio Workbench has some standard requirements listed in each example. -Each example will need the following to run correctly: +Each example needs the following to run correctly: - PostgreSQL database specified in the Workbench configuration - License key or file specified diff --git a/images/favicon.svg b/images/favicon.svg new file mode 100644 index 00000000..d154019f --- /dev/null +++ b/images/favicon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/images/posit-guide-dm.svg b/images/posit-guide-dm.svg new file mode 100644 index 00000000..b0c67d11 --- /dev/null +++ b/images/posit-guide-dm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/posit-guide-ltmd.svg b/images/posit-guide-ltmd.svg new file mode 100644 index 00000000..f2c33c23 --- /dev/null +++ b/images/posit-guide-ltmd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/posit-guide-open-dm.svg b/images/posit-guide-open-dm.svg new file mode 100644 index 00000000..d6b0e2b2 --- /dev/null +++ b/images/posit-guide-open-dm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/posit-guide-open-ltmd.svg b/images/posit-guide-open-ltmd.svg new file mode 100644 index 00000000..77464c09 --- /dev/null +++ b/images/posit-guide-open-ltmd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/posit-icon-fullcolor.svg b/images/posit-icon-fullcolor.svg new file mode 100644 index 00000000..ec7f5525 --- /dev/null +++ b/images/posit-icon-fullcolor.svg @@ -0,0 +1,22 @@ + + + + + + diff --git a/images/posit-logo-black-TM.svg b/images/posit-logo-black-TM.svg new file mode 100644 index 00000000..3b159987 --- /dev/null +++ b/images/posit-logo-black-TM.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/posit-logo-fullcolor-TM.svg b/images/posit-logo-fullcolor-TM.svg new file mode 100644 index 00000000..30512e6b --- /dev/null +++ b/images/posit-logo-fullcolor-TM.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/index.qmd b/index.qmd index 319ec014..bc20cc3b 100644 --- a/index.qmd +++ b/index.qmd @@ -1,20 +1,22 @@ -# Posit Helm Charts +--- +title: Posit Helm Charts +--- [![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/rstudio)](https://artifacthub.io/packages/search?repo=rstudio) [![GitHub license](https://img.shields.io/github/license/rstudio/helm.svg)](https://github.com/rstudio/helm/blob/main/LICENSE) ## Usage -1. Install [Helm](https://helm.sh). Please refer to Helm's [documentation](https://helm.sh/docs/) for more information on getting started. +1. Install [Helm](https://helm.sh). Please refer to the [Helm documentation](https://helm.sh/docs/) for more information on getting started. -2. Add the Posit Helm repo: +2. Add the Posit Helm repository: - ```console + ```{.bash} helm repo add rstudio https://helm.rstudio.com ``` 3. View charts: - ```console + ```{.bash} helm search repo rstudio - ``` + ``` \ No newline at end of file diff --git a/other-charts/prepull-daemonset/Chart.yaml b/other-charts/prepull-daemonset/Chart.yaml index 97c8fe24..bc72a7e6 100644 --- a/other-charts/prepull-daemonset/Chart.yaml +++ b/other-charts/prepull-daemonset/Chart.yaml @@ -1,6 +1,6 @@ name: prepull-daemonset description: a daemonset to prepull images so they are cached -version: 0.0.3 +version: 0.0.4 apiVersion: v2 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png home: https://www.rstudio.com diff --git a/other-charts/prepull-daemonset/NEWS.md b/other-charts/prepull-daemonset/NEWS.md index c7b0f049..8c4894c5 100644 --- a/other-charts/prepull-daemonset/NEWS.md +++ b/other-charts/prepull-daemonset/NEWS.md @@ -1,5 +1,9 @@ # Changelog +## 0.0.4 + +- Update docs + ## 0.0.3 - Updates to support standalone documentation site diff --git a/other-charts/prepull-daemonset/README.md b/other-charts/prepull-daemonset/README.md index 5f5492b0..a8c757e1 100644 --- a/other-charts/prepull-daemonset/README.md +++ b/other-charts/prepull-daemonset/README.md @@ -1,16 +1,16 @@ # prepull-daemonset -![Version: 0.0.3](https://img.shields.io/badge/Version-0.0.3-informational?style=flat-square) +![Version: 0.0.4](https://img.shields.io/badge/Version-0.0.4-informational?style=flat-square) #### _a daemonset to prepull images so they are cached_ ## Installing the Chart -To install the chart with the release name `my-release` at version 0.0.3: +To install the chart with the release name `my-release` at version 0.0.4: ```bash helm repo add rstudio https://helm.rstudio.com -helm install my-release rstudio/prepull-daemonset --version=0.0.3 +helm install my-release rstudio/prepull-daemonset --version=0.0.4 ``` ## Use @@ -54,5 +54,5 @@ kubectl rollout restart daemonset/prepull-daemonset | updateStrategy | object | `{}` | | ---------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0) +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1)