Skip to content

Commit

Permalink
feat(images): Add RStudio (#2410)
Browse files Browse the repository at this point in the history
Signed-off-by: RJ Sampson <[email protected]>
  • Loading branch information
EyeCantCU authored Mar 27, 2024
1 parent 9507796 commit ae0474f
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 0 deletions.
38 changes: 38 additions & 0 deletions images/rstudio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!--monopod:start-->
# rstudio
| | |
| - | - |
| **OCI Reference** | `cgr.dev/chainguard/rstudio` |


* [View Image in Chainguard Academy](https://edu.chainguard.dev/chainguard/chainguard-images/reference/rstudio/overview/)
* [View Image Catalog](https://console.enforce.dev/images/catalog) for a full list of available tags.
* [Contact Chainguard](https://www.chainguard.dev/chainguard-images) for enterprise support, SLAs, and access to older tags.*

---
<!--monopod:end-->

<!--overview:start-->
Minimal [RStudio](https://github.com/rstudio/rstudio) container image.
<!--overview:end-->

<!--getting:start-->
## Download this Image
The image is available on `cgr.dev`:

```
docker pull cgr.dev/chainguard/rstudio:latest
```
<!--getting:end-->

<!--body:start-->
## Running the Image
In order to run RStudio, execute the following command in a terminal:

```bash
docker run -it -p 8787:8787 cgr.dev/chainguard/rstudio:latest
```

The server will now start and the IDE will be accessible at [localhost:8787](http://localhost:8787) in your browser of choice.

<!--body:end-->
89 changes: 89 additions & 0 deletions images/rstudio/config/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
terraform {
required_providers {
apko = { source = "chainguard-dev/apko" }
}
}

variable "extra_packages" {
description = "Additional packages to install."
type = list(string)
default = ["rstudio"]
}

variable "environment" {
default = {}
}

module "accts" {
source = "../../../tflib/accts"
run-as = 65532
uid = 65532
gid = 65532
name = "rstudio-server"
}

output "config" {
value = jsonencode({
contents = {
packages = var.extra_packages
}
accounts = module.accts.block
environment = merge({
"CRAN" : "https://cloud.r-project.org"
"USER" : "rstudio-server"
"LANG" : "en_US.UTF-8"
"LANG_WHICH" : "en"
"LANG_WHERE" : "US"
"ENCODING" : "UTF-8"
"LANGUAGE" : "en_US.UTF-8"
"LC_CTYPE" : "en_US"
"TZ" : "UTC"
})
entrypoint = {
command = "/usr/bin/rserver"
}
paths = [{
path = "/etc/R"
type = "directory"
uid = module.accts.uid
gid = module.accts.gid
permissions = 509
recursive = true
}, {
path = "/etc/rstudio"
type = "directory"
uid = module.accts.uid
gid = module.accts.gid
permissions = 509
recursive = true
}, {
path = "/usr/lib/R"
type = "directory"
uid = module.accts.uid
gid = module.accts.gid
permissions = 509
recursive = true
}, {
path = "/usr/share/doc/R"
type = "directory"
uid = module.accts.uid
gid = module.accts.gid
permissions = 509
recursive = true
}, {
path = "/var/run/rstudio-server"
type = "directory"
uid = module.accts.uid
gid = module.accts.gid
permissions = 509
recursive = true
}, {
path = "/var/lib/rstudio-server"
type = "directory"
uid = module.accts.uid
gid = module.accts.gid
permissions = 509
recursive = true
}]
})
}
39 changes: 39 additions & 0 deletions images/rstudio/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
terraform {
required_providers {
oci = { source = "chainguard-dev/oci" }
}
}

variable "target_repository" {
description = "The docker repo into which the image and attestations should be published."
}

module "config" {
source = "./config"
}

module "latest" {
source = "../../tflib/publisher"
name = basename(path.module)
target_repository = var.target_repository
config = module.config.config
build-dev = true
}

module "test" {
source = "./tests"

digest = module.latest.image_ref
}

resource "oci_tag" "latest" {
depends_on = [module.test]
digest_ref = module.latest.image_ref
tag = "latest"
}

resource "oci_tag" "latest-dev" {
depends_on = [module.test]
digest_ref = module.latest.dev_ref
tag = "latest-dev"
}
12 changes: 12 additions & 0 deletions images/rstudio/metadata.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: rstudio
image: cgr.dev/chainguard/rstudio
logo: https://storage.googleapis.com/chainguard-academy/logos/rstudio.svg
endoflife: ""
console_summary: ""
short_description: Minimal [RStudio](https://github.com/rstudio/rstudio) container image.
compatibility_notes: ""
readme_file: README.md
upstream_url: https://github.com/rstudio/rstudio
keywords:
- application
- ide
16 changes: 16 additions & 0 deletions images/rstudio/tests/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
terraform {
required_providers {
oci = { source = "chainguard-dev/oci" }
}
}

variable "digest" {
description = "The image digest to run tests over."
}

data "oci_string" "ref" { input = var.digest }

data "oci_exec_test" "smoke" {
digest = var.digest
script = "${path.module}/smoke.sh"
}
106 changes: 106 additions & 0 deletions images/rstudio/tests/smoke.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env bash

set -o errexit -o nounset -o errtrace -o pipefail -x

CONTAINER_NAME="rstudio-$(uuidgen)"

RSTUDIO_PORT="${FREE_PORT}"

REQUEST_RETRIES=10
RETRY_DELAY=15

declare -a expected_logs=(
"Adding user to cache"
"Running as server user"
"Initialized file locks"
"Connecting to sqlite3 database"
"Creating database connection pool"
"Creating secure key file"
"Using secure key file"
)
declare -a missing_logs=()

# Validate RStudio installation
# Must be ran before server starts
docker run \
--rm \
-p "${RSTUDIO_PORT}":"${RSTUDIO_PORT}" \
-e "RS_LOG_LEVEL=debug" \
-e "RS_LOGGER_TYPE=stderr" \
--name "${CONTAINER_NAME}" \
--entrypoint rstudio-server \
"${IMAGE_NAME}" \
verify-installation

# Run RStudio server
docker run \
-d --rm \
-p "${RSTUDIO_PORT}":"${RSTUDIO_PORT}" \
-e "RS_LOG_LEVEL=debug" \
-e "RS_LOGGER_TYPE=stderr" \
--name "${CONTAINER_NAME}" \
"${IMAGE_NAME}" \
--www-port "${RSTUDIO_PORT}"

# Stop container when script exits
trap "docker stop ${CONTAINER_NAME}" EXIT

# Validate that RStudio container logs contain expected log messages.
TEST_validate_container_logs() {
for ((i=1; i<=${REQUEST_RETRIES}; i++)); do
local logs=$(docker logs "${CONTAINER_NAME}" 2>&1)
local logs_found=true

# Search the container logs for our expected log lines.
for log in "${expected_logs[@]}"; do
if ! echo "$logs" | grep -Fq "$log"; then
logs_found=false
fi
done

if $logs_found; then
return 0
elif [[ $i -lt ${REQUEST_RETRIES} ]]; then
echo "Some expected logs were missing. Retrying in ${RETRY_DELAY} seconds..."
sleep ${RETRY_DELAY}
fi
done

# After all retries, record the missing logs
for log in "${expected_logs[@]}"; do
if ! echo "${logs}" | grep -Fq "$log"; then
missing_logs+=("${log}")
fi
done

echo "FAILED: The following log lines where not found:"
printf '%s\n' "${missing_logs[@]}"
exit 1
}

# Check that RStudio responds 200 HTTP status code indicating it's operational.
TEST_http_response() {
for ((i=1; i<=${REQUEST_RETRIES}; i++)); do
if [ $(curl -o /dev/null -s -w "%{http_code}" "http://localhost:${RSTUDIO_PORT}/unsupported_browser.htm") -eq 200 ]; then
return 0
fi
sleep ${RETRY_DELAY}
done

echo "FAILED: Did not receive 200 HTTP response from RStudio after ${REQUEST_RETRIES} attempts."
exit 1
}

TEST_install_package() {
# Install R package
docker exec "${CONTAINER_NAME}" \
Rscript -e 'install.packages("ggplot2", repos = "https://cloud.r-project.org")'

# Import library
docker exec "${CONTAINER_NAME}" \
Rscript -e 'library("ggplot2")'
}

TEST_validate_container_logs
TEST_http_response
TEST_install_package
5 changes: 5 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,11 @@ module "rqlite" {
target_repository = "${var.target_repository}/rqlite"
}

module "rstudio" {
source = "./images/rstudio"
target_repository = "${var.target_repository}/rstudio"
}

module "ruby" {
source = "./images/ruby"
target_repository = "${var.target_repository}/ruby"
Expand Down

0 comments on commit ae0474f

Please sign in to comment.