From c4e1c2f3d649c742627a4bc30575a998f5461767 Mon Sep 17 00:00:00 2001 From: Ian Pittwood Date: Mon, 31 Jul 2023 13:27:51 -0700 Subject: [PATCH 1/5] Update rstudio-pm chart to use /opt/R/default for the R path --- charts/rstudio-pm/Chart.yaml | 2 +- charts/rstudio-pm/NEWS.md | 4 + charts/rstudio-pm/README.md | 164 ++++++++++++------------ charts/rstudio-pm/ci/all-values.yaml | 2 +- charts/rstudio-pm/ci/simple-values.yaml | 2 +- charts/rstudio-pm/values.yaml | 2 +- 6 files changed, 90 insertions(+), 86 deletions(-) diff --git a/charts/rstudio-pm/Chart.yaml b/charts/rstudio-pm/Chart.yaml index 4ce1995e..d82eb6ef 100644 --- a/charts/rstudio-pm/Chart.yaml +++ b/charts/rstudio-pm/Chart.yaml @@ -1,6 +1,6 @@ name: rstudio-pm description: Official Helm chart for RStudio Package Manager -version: 0.5.12 +version: 0.6.0 apiVersion: v2 appVersion: 2023.04.0 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png diff --git a/charts/rstudio-pm/NEWS.md b/charts/rstudio-pm/NEWS.md index d191d338..3495d5f8 100644 --- a/charts/rstudio-pm/NEWS.md +++ b/charts/rstudio-pm/NEWS.md @@ -1,3 +1,7 @@ +# 0.6.0 + +- Change R path to `/opt/R/default`, a generic symlink to the primary R version in the image. + # 0.5.11 - Add `topologySpreadConstraints` values diff --git a/charts/rstudio-pm/README.md b/charts/rstudio-pm/README.md index a3dacc35..818bb819 100644 --- a/charts/rstudio-pm/README.md +++ b/charts/rstudio-pm/README.md @@ -1,6 +1,6 @@ # RStudio Package Manager -![Version: 0.5.12](https://img.shields.io/badge/Version-0.5.12-informational?style=flat-square) ![AppVersion: 2023.04.0](https://img.shields.io/badge/AppVersion-2023.04.0-informational?style=flat-square) +![Version: 0.6.0](https://img.shields.io/badge/Version-0.6.0-informational?style=flat-square) ![AppVersion: 2023.04.0](https://img.shields.io/badge/AppVersion-2023.04.0-informational?style=flat-square) #### _Official Helm chart for RStudio Package Manager_ @@ -21,11 +21,11 @@ To ensure a stable production deployment, please: ## Installing the Chart -To install the chart with the release name `my-release` at version 0.5.12: +To install the chart with the release name `my-release` at version 0.6.0: ```bash helm repo add rstudio https://helm.rstudio.com -helm upgrade --install my-release rstudio/rstudio-pm --version=0.5.12 +helm upgrade --install my-release rstudio/rstudio-pm --version=0.6.0 ``` To explore other chart versions, take a look at: @@ -114,86 +114,86 @@ The Helm `config` values are converted into the `rstudio-pm.gcfg` service config ## Values -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| affinity | object | `{}` | A map used verbatim as the pod's "affinity" definition | -| args | bool | `false` | args is the pod's run arguments. By default, it uses the container's default | -| awsAccessKeyId | bool | `false` | awsAccessKeyId is the access key id for s3 access, used also to gate file creation | -| awsSecretAccessKey | string | `nil` | awsSecretAccessKey is the secret access key, needs to be filled if access_key_id is | -| command | bool | `false` | command is the pod's run command. By default, it uses the container's default | -| config | object | `{"HTTP":{"Listen":":4242"},"Metrics":{"Enabled":true},"Server":{"RVersion":"/opt/R/3.6.2/"}}` | config is a nested map of maps that generates the rstudio-pm.gcfg file | -| enableMigration | bool | `true` | Enable migrations for shared storage (if necessary) using Helm hooks. | -| enableSandboxing | bool | `true` | Enable sandboxing of Git builds, which requires elevated security privileges for the Package Manager container. | -| extraContainers | list | `[]` | sidecar container list | -| extraObjects | list | `[]` | Extra objects to deploy (value evaluated as a template) | -| fullnameOverride | string | `""` | the full name of the release (can be overridden) | -| image.imagePullPolicy | string | `"IfNotPresent"` | the imagePullPolicy for the main pod image | -| image.imagePullSecrets | list | `[]` | an array of kubernetes secrets for pulling the main pod image from private registries | -| image.repository | string | `"rstudio/rstudio-package-manager"` | the repository to use for the main pod image | -| image.tag | string | `""` | the tag to use for the main pod image | -| image.tagPrefix | string | `"bionic-"` | A tag prefix for the server image (common selections: bionic-, jammy-). Only used if tag is not defined | -| ingress.annotations | object | `{}` | | -| ingress.enabled | bool | `false` | | -| ingress.hosts | string | `nil` | | -| ingress.ingressClassName | string | `""` | The ingressClassName for the ingress resource. Only used for clusters that support networking.k8s.io/v1 Ingress resources | -| ingress.tls | list | `[]` | | -| initContainers | bool | `false` | the initContainer spec that will be used verbatim | -| 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.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 | -| license.server | bool | `false` | server is the : for a license server | -| livenessProbe | object | `{"enabled":false,"failureThreshold":10,"httpGet":{"path":"/__ping__","port":4242},"initialDelaySeconds":10,"periodSeconds":5,"timeoutSeconds":2}` | livenessProbe is used to configure the container's livenessProbe | -| nameOverride | string | `""` | the name of the chart deployment (can be overridden) | -| nodeSelector | object | `{}` | A map used verbatim as the pod's "nodeSelector" definition | -| pod.annotations | object | `{}` | annotations is a map of keys / values that will be added as annotations to the pods | +| Key | Type | Default | Description | +|-----|------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| +| affinity | object | `{}` | A map used verbatim as the pod's "affinity" definition | +| args | bool | `false` | args is the pod's run arguments. By default, it uses the container's default | +| awsAccessKeyId | bool | `false` | awsAccessKeyId is the access key id for s3 access, used also to gate file creation | +| awsSecretAccessKey | string | `nil` | awsSecretAccessKey is the secret access key, needs to be filled if access_key_id is | +| command | bool | `false` | command is the pod's run command. By default, it uses the container's default | +| config | object | `{"HTTP":{"Listen":":4242"},"Metrics":{"Enabled":true},"Server":{"RVersion":"/opt/R/default/"}}` | config is a nested map of maps that generates the rstudio-pm.gcfg file | +| enableMigration | bool | `true` | Enable migrations for shared storage (if necessary) using Helm hooks. | +| enableSandboxing | bool | `true` | Enable sandboxing of Git builds, which requires elevated security privileges for the Package Manager container. | +| extraContainers | list | `[]` | sidecar container list | +| extraObjects | list | `[]` | Extra objects to deploy (value evaluated as a template) | +| fullnameOverride | string | `""` | the full name of the release (can be overridden) | +| image.imagePullPolicy | string | `"IfNotPresent"` | the imagePullPolicy for the main pod image | +| image.imagePullSecrets | list | `[]` | an array of kubernetes secrets for pulling the main pod image from private registries | +| image.repository | string | `"rstudio/rstudio-package-manager"` | the repository to use for the main pod image | +| image.tag | string | `""` | the tag to use for the main pod image | +| image.tagPrefix | string | `"bionic-"` | A tag prefix for the server image (common selections: bionic-, jammy-). Only used if tag is not defined | +| ingress.annotations | object | `{}` | | +| ingress.enabled | bool | `false` | | +| ingress.hosts | string | `nil` | | +| ingress.ingressClassName | string | `""` | The ingressClassName for the ingress resource. Only used for clusters that support networking.k8s.io/v1 Ingress resources | +| ingress.tls | list | `[]` | | +| initContainers | bool | `false` | the initContainer spec that will be used verbatim | +| 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.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 | +| license.server | bool | `false` | server is the : for a license server | +| livenessProbe | object | `{"enabled":false,"failureThreshold":10,"httpGet":{"path":"/__ping__","port":4242},"initialDelaySeconds":10,"periodSeconds":5,"timeoutSeconds":2}` | livenessProbe is used to configure the container's livenessProbe | +| nameOverride | string | `""` | the name of the chart deployment (can be overridden) | +| nodeSelector | object | `{}` | A map used verbatim as the pod's "nodeSelector" definition | +| pod.annotations | object | `{}` | annotations is a map of keys / values that will be added as annotations to the pods | | pod.containerSecurityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"runAsNonRoot":true,"runAsUser":999,"seccompProfile":{"type":"{{ if .Values.enableSandboxing }}Unconfined{{ else }}RuntimeDefault{{ end }}"}}` | the [securityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the main Package Manager container. Evaluated as a template. | -| 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.serviceAccountName | string | `""` | Deprecated, use `serviceAccount.name` instead | -| pod.volumeMounts | list | `[]` | volumeMounts is an array of maps that is injected as-is into the "volumeMounts" component of the pod spec | -| pod.volumes | list | `[]` | volumes is 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 | -| readinessProbe | object | `{"enabled":true,"failureThreshold":3,"httpGet":{"path":"/__ping__","port":4242},"initialDelaySeconds":3,"periodSeconds":3,"successThreshold":1,"timeoutSeconds":1}` | readinessProbe is used to configure the container's readinessProbe | -| replicas | int | `1` | replicas is the number of replica pods to maintain for this service | -| resources | object | `{"limits":{"cpu":"2000m","enabled":false,"ephemeralStorage":"200Mi","memory":"4Gi"},"requests":{"cpu":"100m","enabled":false,"ephemeralStorage":"100Mi","memory":"2Gi"}}` | resources define requests and limits for the rstudio-pm pod | -| rootCheckIsFatal | bool | `true` | Whether the check for root accounts in the config file is fatal. This is meant to simplify migration to the new helm chart version. | -| rstudioPMKey | bool | `false` | rstudioPMKey is the rstudio-pm key used for the RStudio Package Manager service | -| service.annotations | object | `{}` | Annotations for the service, for example to specify [an internal load balancer](https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer) | -| service.clusterIP | string | `""` | The cluster-internal IP to use with `service.type` ClusterIP | -| service.loadBalancerIP | string | `""` | The external IP to use with `service.type` LoadBalancer, when supported by the cloud provider | -| service.nodePort | bool | `false` | The explicit nodePort to use for `service.type` NodePort. If not provided, Kubernetes will choose one automatically | -| service.port | int | `80` | The Service port. This is the port your service will run under. | -| 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.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 | -| serviceMonitor.namespace | string | `""` | Namespace to create the ServiceMonitor in (usually the same as the one in which the Operator is running). Defaults to the release namespace | -| sharedStorage.accessModes | list | `["ReadWriteMany"]` | accessModes defined for the storage PVC (represented as YAML) | -| sharedStorage.annotations | object | `{"helm.sh/resource-policy":"keep"}` | Define the annotations for the Persistent Volume Claim resource | -| sharedStorage.create | bool | `false` | whether to create the persistentVolumeClaim for shared storage | -| sharedStorage.mount | bool | `false` | Whether the persistentVolumeClaim should be mounted (even if not created) | -| sharedStorage.name | string | `""` | The name of the pvc. By default, computes a value from the release name | -| sharedStorage.path | string | `"/var/lib/rstudio-pm"` | the path to mount the sharedStorage claim within the pod | -| sharedStorage.requests.storage | string | `"10Gi"` | the volume of storage to request for this persistent volume claim | -| 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.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 | -| topologySpreadConstraints | list | `[]` | An array used verbatim as the pod's "topologySpreadConstraints" definition | -| 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 | +| 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.serviceAccountName | string | `""` | Deprecated, use `serviceAccount.name` instead | +| pod.volumeMounts | list | `[]` | volumeMounts is an array of maps that is injected as-is into the "volumeMounts" component of the pod spec | +| pod.volumes | list | `[]` | volumes is 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 | +| readinessProbe | object | `{"enabled":true,"failureThreshold":3,"httpGet":{"path":"/__ping__","port":4242},"initialDelaySeconds":3,"periodSeconds":3,"successThreshold":1,"timeoutSeconds":1}` | readinessProbe is used to configure the container's readinessProbe | +| replicas | int | `1` | replicas is the number of replica pods to maintain for this service | +| resources | object | `{"limits":{"cpu":"2000m","enabled":false,"ephemeralStorage":"200Mi","memory":"4Gi"},"requests":{"cpu":"100m","enabled":false,"ephemeralStorage":"100Mi","memory":"2Gi"}}` | resources define requests and limits for the rstudio-pm pod | +| rootCheckIsFatal | bool | `true` | Whether the check for root accounts in the config file is fatal. This is meant to simplify migration to the new helm chart version. | +| rstudioPMKey | bool | `false` | rstudioPMKey is the rstudio-pm key used for the RStudio Package Manager service | +| service.annotations | object | `{}` | Annotations for the service, for example to specify [an internal load balancer](https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer) | +| service.clusterIP | string | `""` | The cluster-internal IP to use with `service.type` ClusterIP | +| service.loadBalancerIP | string | `""` | The external IP to use with `service.type` LoadBalancer, when supported by the cloud provider | +| service.nodePort | bool | `false` | The explicit nodePort to use for `service.type` NodePort. If not provided, Kubernetes will choose one automatically | +| service.port | int | `80` | The Service port. This is the port your service will run under. | +| 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.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 | +| serviceMonitor.namespace | string | `""` | Namespace to create the ServiceMonitor in (usually the same as the one in which the Operator is running). Defaults to the release namespace | +| sharedStorage.accessModes | list | `["ReadWriteMany"]` | accessModes defined for the storage PVC (represented as YAML) | +| sharedStorage.annotations | object | `{"helm.sh/resource-policy":"keep"}` | Define the annotations for the Persistent Volume Claim resource | +| sharedStorage.create | bool | `false` | whether to create the persistentVolumeClaim for shared storage | +| sharedStorage.mount | bool | `false` | Whether the persistentVolumeClaim should be mounted (even if not created) | +| sharedStorage.name | string | `""` | The name of the pvc. By default, computes a value from the release name | +| sharedStorage.path | string | `"/var/lib/rstudio-pm"` | the path to mount the sharedStorage claim within the pod | +| sharedStorage.requests.storage | string | `"10Gi"` | the volume of storage to request for this persistent volume claim | +| 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.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 | +| topologySpreadConstraints | list | `[]` | An array used verbatim as the pod's "topologySpreadConstraints" definition | +| 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) diff --git a/charts/rstudio-pm/ci/all-values.yaml b/charts/rstudio-pm/ci/all-values.yaml index 6df3a720..0c60d45d 100644 --- a/charts/rstudio-pm/ci/all-values.yaml +++ b/charts/rstudio-pm/ci/all-values.yaml @@ -27,7 +27,7 @@ config: Server: DataDir: /var/lib/rstudio-pm RVersion: - - /opt/R/3.6.2 + - /opt/R/default Git: BuilderDir: "/tmp/git" rstudioPMKey: somevalue diff --git a/charts/rstudio-pm/ci/simple-values.yaml b/charts/rstudio-pm/ci/simple-values.yaml index feea86b1..534069dc 100644 --- a/charts/rstudio-pm/ci/simple-values.yaml +++ b/charts/rstudio-pm/ci/simple-values.yaml @@ -9,6 +9,6 @@ config: Server: DataDir: /var/lib/rstudio-pm RVersion: - - /opt/R/3.6.2 + - /opt/R/default Git: BuilderDir: "/tmp/git" diff --git a/charts/rstudio-pm/values.yaml b/charts/rstudio-pm/values.yaml index eef939de..c6c65f19 100644 --- a/charts/rstudio-pm/values.yaml +++ b/charts/rstudio-pm/values.yaml @@ -230,7 +230,7 @@ serviceMonitor: # -- config is a nested map of maps that generates the rstudio-pm.gcfg file config: Server: - RVersion: "/opt/R/3.6.2/" + RVersion: "/opt/R/default/" HTTP: Listen: :4242 Metrics: From d56d60278432275551fcd37acfae40d6f02a2dcd Mon Sep 17 00:00:00 2001 From: Ian Pittwood Date: Mon, 31 Jul 2023 13:28:13 -0700 Subject: [PATCH 2/5] Update rstudio-connect ci Python and R paths Update helm-docs and README.md Update rbac yaml --- charts/rstudio-connect/ci/complex-values.yaml | 4 +- charts/rstudio-connect/ci/simple-values.yaml | 4 +- charts/rstudio-pm/README.md | 158 +++++++++--------- 3 files changed, 83 insertions(+), 83 deletions(-) diff --git a/charts/rstudio-connect/ci/complex-values.yaml b/charts/rstudio-connect/ci/complex-values.yaml index 37f77cd8..b2151072 100644 --- a/charts/rstudio-connect/ci/complex-values.yaml +++ b/charts/rstudio-connect/ci/complex-values.yaml @@ -137,7 +137,7 @@ config: Provider: password Python: Enabled: true - Executable: /opt/python/3.6.5/bin/python + Executable: /opt/python/default/bin/python 'RPackageRepository "CRAN"': URL: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest 'RPackageRepository "RSPM"': @@ -147,4 +147,4 @@ config: DataDir: /var/lib/rstudio-connect RVersionScanning: false RVersion: - - /opt/R/3.6.2 + - /opt/R/default diff --git a/charts/rstudio-connect/ci/simple-values.yaml b/charts/rstudio-connect/ci/simple-values.yaml index 0d8cacb2..964d534b 100644 --- a/charts/rstudio-connect/ci/simple-values.yaml +++ b/charts/rstudio-connect/ci/simple-values.yaml @@ -13,7 +13,7 @@ config: Provider: password Python: Enabled: true - Executable: /opt/python/3.6.5/bin/python + Executable: /opt/python/default/bin/python 'RPackageRepository "CRAN"': URL: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest 'RPackageRepository "RSPM"': @@ -23,4 +23,4 @@ config: DataDir: /var/lib/rstudio-connect RVersionScanning: false RVersion: - - /opt/R/3.6.2 + - /opt/R/default diff --git a/charts/rstudio-pm/README.md b/charts/rstudio-pm/README.md index 818bb819..0c20b664 100644 --- a/charts/rstudio-pm/README.md +++ b/charts/rstudio-pm/README.md @@ -114,86 +114,86 @@ The Helm `config` values are converted into the `rstudio-pm.gcfg` service config ## Values -| Key | Type | Default | Description | -|-----|------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| -| affinity | object | `{}` | A map used verbatim as the pod's "affinity" definition | -| args | bool | `false` | args is the pod's run arguments. By default, it uses the container's default | -| awsAccessKeyId | bool | `false` | awsAccessKeyId is the access key id for s3 access, used also to gate file creation | -| awsSecretAccessKey | string | `nil` | awsSecretAccessKey is the secret access key, needs to be filled if access_key_id is | -| command | bool | `false` | command is the pod's run command. By default, it uses the container's default | -| config | object | `{"HTTP":{"Listen":":4242"},"Metrics":{"Enabled":true},"Server":{"RVersion":"/opt/R/default/"}}` | config is a nested map of maps that generates the rstudio-pm.gcfg file | -| enableMigration | bool | `true` | Enable migrations for shared storage (if necessary) using Helm hooks. | -| enableSandboxing | bool | `true` | Enable sandboxing of Git builds, which requires elevated security privileges for the Package Manager container. | -| extraContainers | list | `[]` | sidecar container list | -| extraObjects | list | `[]` | Extra objects to deploy (value evaluated as a template) | -| fullnameOverride | string | `""` | the full name of the release (can be overridden) | -| image.imagePullPolicy | string | `"IfNotPresent"` | the imagePullPolicy for the main pod image | -| image.imagePullSecrets | list | `[]` | an array of kubernetes secrets for pulling the main pod image from private registries | -| image.repository | string | `"rstudio/rstudio-package-manager"` | the repository to use for the main pod image | -| image.tag | string | `""` | the tag to use for the main pod image | -| image.tagPrefix | string | `"bionic-"` | A tag prefix for the server image (common selections: bionic-, jammy-). Only used if tag is not defined | -| ingress.annotations | object | `{}` | | -| ingress.enabled | bool | `false` | | -| ingress.hosts | string | `nil` | | -| ingress.ingressClassName | string | `""` | The ingressClassName for the ingress resource. Only used for clusters that support networking.k8s.io/v1 Ingress resources | -| ingress.tls | list | `[]` | | -| initContainers | bool | `false` | the initContainer spec that will be used verbatim | -| 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.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 | -| license.server | bool | `false` | server is the : for a license server | -| livenessProbe | object | `{"enabled":false,"failureThreshold":10,"httpGet":{"path":"/__ping__","port":4242},"initialDelaySeconds":10,"periodSeconds":5,"timeoutSeconds":2}` | livenessProbe is used to configure the container's livenessProbe | -| nameOverride | string | `""` | the name of the chart deployment (can be overridden) | -| nodeSelector | object | `{}` | A map used verbatim as the pod's "nodeSelector" definition | -| pod.annotations | object | `{}` | annotations is a map of keys / values that will be added as annotations to the pods | +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | A map used verbatim as the pod's "affinity" definition | +| args | bool | `false` | args is the pod's run arguments. By default, it uses the container's default | +| awsAccessKeyId | bool | `false` | awsAccessKeyId is the access key id for s3 access, used also to gate file creation | +| awsSecretAccessKey | string | `nil` | awsSecretAccessKey is the secret access key, needs to be filled if access_key_id is | +| command | bool | `false` | command is the pod's run command. By default, it uses the container's default | +| config | object | `{"HTTP":{"Listen":":4242"},"Metrics":{"Enabled":true},"Server":{"RVersion":"/opt/R/default/"}}` | config is a nested map of maps that generates the rstudio-pm.gcfg file | +| enableMigration | bool | `true` | Enable migrations for shared storage (if necessary) using Helm hooks. | +| enableSandboxing | bool | `true` | Enable sandboxing of Git builds, which requires elevated security privileges for the Package Manager container. | +| extraContainers | list | `[]` | sidecar container list | +| extraObjects | list | `[]` | Extra objects to deploy (value evaluated as a template) | +| fullnameOverride | string | `""` | the full name of the release (can be overridden) | +| image.imagePullPolicy | string | `"IfNotPresent"` | the imagePullPolicy for the main pod image | +| image.imagePullSecrets | list | `[]` | an array of kubernetes secrets for pulling the main pod image from private registries | +| image.repository | string | `"rstudio/rstudio-package-manager"` | the repository to use for the main pod image | +| image.tag | string | `""` | the tag to use for the main pod image | +| image.tagPrefix | string | `"bionic-"` | A tag prefix for the server image (common selections: bionic-, jammy-). Only used if tag is not defined | +| ingress.annotations | object | `{}` | | +| ingress.enabled | bool | `false` | | +| ingress.hosts | string | `nil` | | +| ingress.ingressClassName | string | `""` | The ingressClassName for the ingress resource. Only used for clusters that support networking.k8s.io/v1 Ingress resources | +| ingress.tls | list | `[]` | | +| initContainers | bool | `false` | the initContainer spec that will be used verbatim | +| 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.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 | +| license.server | bool | `false` | server is the : for a license server | +| livenessProbe | object | `{"enabled":false,"failureThreshold":10,"httpGet":{"path":"/__ping__","port":4242},"initialDelaySeconds":10,"periodSeconds":5,"timeoutSeconds":2}` | livenessProbe is used to configure the container's livenessProbe | +| nameOverride | string | `""` | the name of the chart deployment (can be overridden) | +| nodeSelector | object | `{}` | A map used verbatim as the pod's "nodeSelector" definition | +| pod.annotations | object | `{}` | annotations is a map of keys / values that will be added as annotations to the pods | | pod.containerSecurityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"runAsNonRoot":true,"runAsUser":999,"seccompProfile":{"type":"{{ if .Values.enableSandboxing }}Unconfined{{ else }}RuntimeDefault{{ end }}"}}` | the [securityContext](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the main Package Manager container. Evaluated as a template. | -| 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.serviceAccountName | string | `""` | Deprecated, use `serviceAccount.name` instead | -| pod.volumeMounts | list | `[]` | volumeMounts is an array of maps that is injected as-is into the "volumeMounts" component of the pod spec | -| pod.volumes | list | `[]` | volumes is 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 | -| readinessProbe | object | `{"enabled":true,"failureThreshold":3,"httpGet":{"path":"/__ping__","port":4242},"initialDelaySeconds":3,"periodSeconds":3,"successThreshold":1,"timeoutSeconds":1}` | readinessProbe is used to configure the container's readinessProbe | -| replicas | int | `1` | replicas is the number of replica pods to maintain for this service | -| resources | object | `{"limits":{"cpu":"2000m","enabled":false,"ephemeralStorage":"200Mi","memory":"4Gi"},"requests":{"cpu":"100m","enabled":false,"ephemeralStorage":"100Mi","memory":"2Gi"}}` | resources define requests and limits for the rstudio-pm pod | -| rootCheckIsFatal | bool | `true` | Whether the check for root accounts in the config file is fatal. This is meant to simplify migration to the new helm chart version. | -| rstudioPMKey | bool | `false` | rstudioPMKey is the rstudio-pm key used for the RStudio Package Manager service | -| service.annotations | object | `{}` | Annotations for the service, for example to specify [an internal load balancer](https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer) | -| service.clusterIP | string | `""` | The cluster-internal IP to use with `service.type` ClusterIP | -| service.loadBalancerIP | string | `""` | The external IP to use with `service.type` LoadBalancer, when supported by the cloud provider | -| service.nodePort | bool | `false` | The explicit nodePort to use for `service.type` NodePort. If not provided, Kubernetes will choose one automatically | -| service.port | int | `80` | The Service port. This is the port your service will run under. | -| 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.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 | -| serviceMonitor.namespace | string | `""` | Namespace to create the ServiceMonitor in (usually the same as the one in which the Operator is running). Defaults to the release namespace | -| sharedStorage.accessModes | list | `["ReadWriteMany"]` | accessModes defined for the storage PVC (represented as YAML) | -| sharedStorage.annotations | object | `{"helm.sh/resource-policy":"keep"}` | Define the annotations for the Persistent Volume Claim resource | -| sharedStorage.create | bool | `false` | whether to create the persistentVolumeClaim for shared storage | -| sharedStorage.mount | bool | `false` | Whether the persistentVolumeClaim should be mounted (even if not created) | -| sharedStorage.name | string | `""` | The name of the pvc. By default, computes a value from the release name | -| sharedStorage.path | string | `"/var/lib/rstudio-pm"` | the path to mount the sharedStorage claim within the pod | -| sharedStorage.requests.storage | string | `"10Gi"` | the volume of storage to request for this persistent volume claim | -| 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.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 | -| topologySpreadConstraints | list | `[]` | An array used verbatim as the pod's "topologySpreadConstraints" definition | -| 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 | +| 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.serviceAccountName | string | `""` | Deprecated, use `serviceAccount.name` instead | +| pod.volumeMounts | list | `[]` | volumeMounts is an array of maps that is injected as-is into the "volumeMounts" component of the pod spec | +| pod.volumes | list | `[]` | volumes is 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 | +| readinessProbe | object | `{"enabled":true,"failureThreshold":3,"httpGet":{"path":"/__ping__","port":4242},"initialDelaySeconds":3,"periodSeconds":3,"successThreshold":1,"timeoutSeconds":1}` | readinessProbe is used to configure the container's readinessProbe | +| replicas | int | `1` | replicas is the number of replica pods to maintain for this service | +| resources | object | `{"limits":{"cpu":"2000m","enabled":false,"ephemeralStorage":"200Mi","memory":"4Gi"},"requests":{"cpu":"100m","enabled":false,"ephemeralStorage":"100Mi","memory":"2Gi"}}` | resources define requests and limits for the rstudio-pm pod | +| rootCheckIsFatal | bool | `true` | Whether the check for root accounts in the config file is fatal. This is meant to simplify migration to the new helm chart version. | +| rstudioPMKey | bool | `false` | rstudioPMKey is the rstudio-pm key used for the RStudio Package Manager service | +| service.annotations | object | `{}` | Annotations for the service, for example to specify [an internal load balancer](https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer) | +| service.clusterIP | string | `""` | The cluster-internal IP to use with `service.type` ClusterIP | +| service.loadBalancerIP | string | `""` | The external IP to use with `service.type` LoadBalancer, when supported by the cloud provider | +| service.nodePort | bool | `false` | The explicit nodePort to use for `service.type` NodePort. If not provided, Kubernetes will choose one automatically | +| service.port | int | `80` | The Service port. This is the port your service will run under. | +| 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.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 | +| serviceMonitor.namespace | string | `""` | Namespace to create the ServiceMonitor in (usually the same as the one in which the Operator is running). Defaults to the release namespace | +| sharedStorage.accessModes | list | `["ReadWriteMany"]` | accessModes defined for the storage PVC (represented as YAML) | +| sharedStorage.annotations | object | `{"helm.sh/resource-policy":"keep"}` | Define the annotations for the Persistent Volume Claim resource | +| sharedStorage.create | bool | `false` | whether to create the persistentVolumeClaim for shared storage | +| sharedStorage.mount | bool | `false` | Whether the persistentVolumeClaim should be mounted (even if not created) | +| sharedStorage.name | string | `""` | The name of the pvc. By default, computes a value from the release name | +| sharedStorage.path | string | `"/var/lib/rstudio-pm"` | the path to mount the sharedStorage claim within the pod | +| sharedStorage.requests.storage | string | `"10Gi"` | the volume of storage to request for this persistent volume claim | +| 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.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 | +| topologySpreadConstraints | list | `[]` | An array used verbatim as the pod's "topologySpreadConstraints" definition | +| 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) From d0eb9daeb5f95fc894ab62e94433f14eb90bebb1 Mon Sep 17 00:00:00 2001 From: Ian Pittwood Date: Tue, 1 Aug 2023 06:31:22 -0700 Subject: [PATCH 3/5] Bump bugfix version instead of minor revision version Update helm-docs and README.md --- charts/rstudio-pm/Chart.yaml | 2 +- charts/rstudio-pm/README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/rstudio-pm/Chart.yaml b/charts/rstudio-pm/Chart.yaml index d82eb6ef..9ea0d70c 100644 --- a/charts/rstudio-pm/Chart.yaml +++ b/charts/rstudio-pm/Chart.yaml @@ -1,6 +1,6 @@ name: rstudio-pm description: Official Helm chart for RStudio Package Manager -version: 0.6.0 +version: 0.5.13 apiVersion: v2 appVersion: 2023.04.0 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png diff --git a/charts/rstudio-pm/README.md b/charts/rstudio-pm/README.md index 0c20b664..45f8904b 100644 --- a/charts/rstudio-pm/README.md +++ b/charts/rstudio-pm/README.md @@ -1,6 +1,6 @@ # RStudio Package Manager -![Version: 0.6.0](https://img.shields.io/badge/Version-0.6.0-informational?style=flat-square) ![AppVersion: 2023.04.0](https://img.shields.io/badge/AppVersion-2023.04.0-informational?style=flat-square) +![Version: 0.5.13](https://img.shields.io/badge/Version-0.5.13-informational?style=flat-square) ![AppVersion: 2023.04.0](https://img.shields.io/badge/AppVersion-2023.04.0-informational?style=flat-square) #### _Official Helm chart for RStudio Package Manager_ @@ -21,11 +21,11 @@ To ensure a stable production deployment, please: ## Installing the Chart -To install the chart with the release name `my-release` at version 0.6.0: +To install the chart with the release name `my-release` at version 0.5.13: ```bash helm repo add rstudio https://helm.rstudio.com -helm upgrade --install my-release rstudio/rstudio-pm --version=0.6.0 +helm upgrade --install my-release rstudio/rstudio-pm --version=0.5.13 ``` To explore other chart versions, take a look at: From 29d081c5eb5b38dfa2e94524fa35c67855e5c291 Mon Sep 17 00:00:00 2001 From: Ian Pittwood Date: Tue, 1 Aug 2023 10:24:47 -0700 Subject: [PATCH 4/5] Revert "Update rstudio-connect ci Python and R paths" This reverts commit ac6c5018f3571d4d95a377e30ec062cf519b29f9. Update helm-docs and README.md Update rbac yaml --- charts/rstudio-connect/ci/complex-values.yaml | 4 ++-- charts/rstudio-connect/ci/simple-values.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/rstudio-connect/ci/complex-values.yaml b/charts/rstudio-connect/ci/complex-values.yaml index b2151072..37f77cd8 100644 --- a/charts/rstudio-connect/ci/complex-values.yaml +++ b/charts/rstudio-connect/ci/complex-values.yaml @@ -137,7 +137,7 @@ config: Provider: password Python: Enabled: true - Executable: /opt/python/default/bin/python + Executable: /opt/python/3.6.5/bin/python 'RPackageRepository "CRAN"': URL: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest 'RPackageRepository "RSPM"': @@ -147,4 +147,4 @@ config: DataDir: /var/lib/rstudio-connect RVersionScanning: false RVersion: - - /opt/R/default + - /opt/R/3.6.2 diff --git a/charts/rstudio-connect/ci/simple-values.yaml b/charts/rstudio-connect/ci/simple-values.yaml index 964d534b..0d8cacb2 100644 --- a/charts/rstudio-connect/ci/simple-values.yaml +++ b/charts/rstudio-connect/ci/simple-values.yaml @@ -13,7 +13,7 @@ config: Provider: password Python: Enabled: true - Executable: /opt/python/default/bin/python + Executable: /opt/python/3.6.5/bin/python 'RPackageRepository "CRAN"': URL: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest 'RPackageRepository "RSPM"': @@ -23,4 +23,4 @@ config: DataDir: /var/lib/rstudio-connect RVersionScanning: false RVersion: - - /opt/R/default + - /opt/R/3.6.2 From 549ee512135ed16a7522631f8fc3e8108fcfe9b6 Mon Sep 17 00:00:00 2001 From: Ian Pittwood Date: Mon, 14 Aug 2023 08:43:23 -0700 Subject: [PATCH 5/5] update NEWS.md version --- charts/rstudio-pm/NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/rstudio-pm/NEWS.md b/charts/rstudio-pm/NEWS.md index 3495d5f8..a90f849f 100644 --- a/charts/rstudio-pm/NEWS.md +++ b/charts/rstudio-pm/NEWS.md @@ -1,4 +1,4 @@ -# 0.6.0 +# 0.5.13 - Change R path to `/opt/R/default`, a generic symlink to the primary R version in the image.