Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/actions/create-kind-cluster/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,18 @@ runs:
host: "${{ inputs.registry-name }}:${{ inputs.registry-port }}"
help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
EOF

- name: Install NFS provisioner for ReadWriteMany PVC support
shell: bash
run: |
# Add NFS provisioner Helm repo (suppress "already exists" errors, but update regardless)
helm repo add nfs-ganesha-server-and-external-provisioner \
https://kubernetes-sigs.github.io/nfs-ganesha-server-and-external-provisioner/ 2>/dev/null || true
helm repo update nfs-ganesha-server-and-external-provisioner

# Install NFS provisioner with RWX support as default storage class
helm install nfs-server nfs-ganesha-server-and-external-provisioner/nfs-server-provisioner \
--set persistence.enabled=false \
--set storageClass.name=nfs \
--set storageClass.defaultClass=true \
--wait --timeout 5m
12 changes: 12 additions & 0 deletions .github/workflows/functional-test-cloud.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,18 @@ jobs:
service-account-private-key-file: /etc/kubernetes/pki/sa.key
EOF

- name: Install NFS provisioner for ReadWriteMany PVC support
run: |
helm repo add nfs-ganesha-server-and-external-provisioner \
https://kubernetes-sigs.github.io/nfs-ganesha-server-and-external-provisioner/ 2>/dev/null || true
helm repo update nfs-ganesha-server-and-external-provisioner

helm install nfs-server nfs-ganesha-server-and-external-provisioner/nfs-server-provisioner \
--set persistence.enabled=false \
--set storageClass.name=nfs \
--set storageClass.defaultClass=true \
--wait --timeout 5m

- name: Install Azure Keyvault CSI driver chart
run: |
helm repo add csi-secrets-store-provider-azure https://azure.github.io/secrets-store-csi-driver-provider-azure/charts
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,6 @@ demo
.copilot-tracking/

.codeql-results

# Go Cache
.gocache/
4 changes: 4 additions & 0 deletions build/configs/ucp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ logging:
level: "debug"
json: true

# Terraform cache path - relative to project root where debug commands are run
terraform:
path: "./debug_files/terraform-cache"

tracerProvider:
enabled: false
serviceName: "ucp"
Expand Down
10 changes: 9 additions & 1 deletion cmd/applications-rp/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"fmt"

"github.com/go-chi/chi/v5"
"github.com/go-logr/logr"
"github.com/spf13/cobra"
runtimelog "sigs.k8s.io/controller-runtime/pkg/log"
Expand All @@ -31,6 +32,7 @@ import (
"github.com/radius-project/radius/pkg/components/trace/traceservice"
"github.com/radius-project/radius/pkg/recipes/controllerconfig"
"github.com/radius-project/radius/pkg/server"
tfinstaller "github.com/radius-project/radius/pkg/terraform/installer"

"github.com/radius-project/radius/pkg/components/hosting"
"github.com/radius-project/radius/pkg/ucp/ucplog"
Expand Down Expand Up @@ -81,10 +83,16 @@ var rootCmd = &cobra.Command{
return err
}

// Create route configurer for terraform installer API endpoints
terraformRoutes := func(ctx context.Context, r chi.Router, opts hostoptions.HostOptions) error {
return tfinstaller.RegisterRoutesWithHostOptions(ctx, r, opts, opts.Config.Server.PathBase)
}

services = append(
services,
server.NewAPIService(options, builders),
server.NewAPIServiceWithRoutes(options, builders, terraformRoutes),
server.NewAsyncWorker(options, builders),
tfinstaller.NewHostOptionsWorkerService(options),
)

host := &hosting.Host{
Expand Down
20 changes: 20 additions & 0 deletions cmd/rad/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ import (
"github.com/radius-project/radius/pkg/cli/cmd/rollback"
rollback_kubernetes "github.com/radius-project/radius/pkg/cli/cmd/rollback/kubernetes"
"github.com/radius-project/radius/pkg/cli/cmd/run"
"github.com/radius-project/radius/pkg/cli/cmd/terraform"
terraform_install "github.com/radius-project/radius/pkg/cli/cmd/terraform/install"
terraform_list "github.com/radius-project/radius/pkg/cli/cmd/terraform/list"
terraform_status "github.com/radius-project/radius/pkg/cli/cmd/terraform/status"
terraform_uninstall "github.com/radius-project/radius/pkg/cli/cmd/terraform/uninstall"
"github.com/radius-project/radius/pkg/cli/cmd/uninstall"
uninstall_kubernetes "github.com/radius-project/radius/pkg/cli/cmd/uninstall/kubernetes"
"github.com/radius-project/radius/pkg/cli/cmd/upgrade"
Expand Down Expand Up @@ -452,6 +457,21 @@ func initSubCommands() {

versionCmd, _ := version.NewCommand(framework)
RootCmd.AddCommand(versionCmd)

terraformCmd := terraform.NewCommand()
RootCmd.AddCommand(terraformCmd)

terraformInstallCmd, _ := terraform_install.NewCommand(framework)
terraformCmd.AddCommand(terraformInstallCmd)

terraformUninstallCmd, _ := terraform_uninstall.NewCommand(framework)
terraformCmd.AddCommand(terraformUninstallCmd)

terraformStatusCmd, _ := terraform_status.NewCommand(framework)
terraformCmd.AddCommand(terraformStatusCmd)

terraformListCmd, _ := terraform_list.NewCommand(framework)
terraformCmd.AddCommand(terraformListCmd)
}

// The dance we do with config is kinda complex. We want commands to be able to retrieve a config (*viper.Viper)
Expand Down
9 changes: 8 additions & 1 deletion deploy/Chart/templates/dynamic-rp/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,10 @@ spec:

echo "Terraform binary successfully pre-downloaded and installed"
volumeMounts:
{{- if eq .Values.global.terraform.enabled true }}
- name: terraform
mountPath: {{ .Values.dynamicrp.terraform.path }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
Expand Down Expand Up @@ -167,8 +169,10 @@ spec:
- name: aws-iam-token
mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
{{- end }}
{{- if eq .Values.global.terraform.enabled true }}
- name: terraform
mountPath: {{ .Values.dynamicrp.terraform.path }}
{{- end }}
- name: encryption-secret
mountPath: /var/secrets/encryption
readOnly: true
Expand Down Expand Up @@ -198,8 +202,11 @@ spec:
expirationSeconds: 86400
audience: "sts.amazonaws.com"
{{- end }}
{{- if eq .Values.global.terraform.enabled true }}
- name: terraform
emptyDir: {}
persistentVolumeClaim:
claimName: terraform-storage
{{- end }}
- name: encryption-secret
secret:
secretName: radius-encryption-key
Expand Down
9 changes: 8 additions & 1 deletion deploy/Chart/templates/rp/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,10 @@ spec:

echo "Terraform binary successfully pre-downloaded and installed"
volumeMounts:
{{- if eq .Values.global.terraform.enabled true }}
- name: terraform
mountPath: {{ .Values.rp.terraform.path }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
Expand Down Expand Up @@ -180,8 +182,10 @@ spec:
- name: aws-iam-token
mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
{{- end }}
{{- if eq .Values.global.terraform.enabled true }}
- name: terraform
mountPath: {{ .Values.rp.terraform.path }}
{{- end }}
{{- if .Values.global.rootCA.cert }}
- name: {{ .Values.global.rootCA.volumeName }}
mountPath: {{ .Values.global.rootCA.mountPath }}
Expand All @@ -208,8 +212,11 @@ spec:
expirationSeconds: 86400
audience: "sts.amazonaws.com"
{{- end }}
{{- if eq .Values.global.terraform.enabled true }}
- name: terraform
emptyDir: {}
persistentVolumeClaim:
claimName: terraform-storage
{{- end }}
{{- if .Values.global.rootCA.cert }}
- name: {{ .Values.global.rootCA.volumeName }}
secret:
Expand Down
19 changes: 19 additions & 0 deletions deploy/Chart/templates/terraform-pvc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{- if .Values.global.terraform.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: terraform-storage
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: terraform-storage
app.kubernetes.io/part-of: radius
spec:
accessModes:
- ReadWriteMany
{{- if .Values.global.terraform.storageClassName }}
storageClassName: {{ .Values.global.terraform.storageClassName | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.global.terraform.storageSize | default "1Gi" }}
{{- end }}
166 changes: 166 additions & 0 deletions deploy/Chart/tests/terraform_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
suite: test terraform configuration
templates:
- rp/deployment.yaml
- rp/configmaps.yaml
- dynamic-rp/deployment.yaml
- terraform-pvc.yaml
tests:
# Terraform PVC tests
- it: should create terraform PVC when terraform is enabled
set:
global.terraform.enabled: true
asserts:
- isKind:
of: PersistentVolumeClaim
template: terraform-pvc.yaml
- equal:
path: metadata.name
value: terraform-storage
template: terraform-pvc.yaml
- contains:
path: spec.accessModes
content: ReadWriteMany
template: terraform-pvc.yaml

- it: should use custom storage class when specified
set:
global.terraform.enabled: true
global.terraform.storageClassName: "nfs"
asserts:
- equal:
path: spec.storageClassName
value: "nfs"
template: terraform-pvc.yaml

- it: should use custom storage size when specified
set:
global.terraform.enabled: true
global.terraform.storageSize: "5Gi"
asserts:
- equal:
path: spec.resources.requests.storage
value: "5Gi"
template: terraform-pvc.yaml

# applications-rp terraform volume tests
- it: should use PVC for terraform volume in applications-rp when terraform is enabled
set:
global.terraform.enabled: true
rp.image: applications-rp
rp.tag: latest
asserts:
- contains:
path: spec.template.spec.volumes
content:
name: terraform
persistentVolumeClaim:
claimName: terraform-storage
template: rp/deployment.yaml

- it: should mount terraform volume in applications-rp container
set:
global.terraform.enabled: true
rp.image: applications-rp
rp.tag: latest
rp.terraform.path: /terraform
asserts:
- contains:
path: spec.template.spec.containers[0].volumeMounts
content:
name: terraform
mountPath: /terraform
template: rp/deployment.yaml

- it: should include terraform init container when terraform is enabled
set:
global.terraform.enabled: true
rp.image: applications-rp
rp.tag: latest
asserts:
- isNotEmpty:
path: spec.template.spec.initContainers
template: rp/deployment.yaml
- contains:
path: spec.template.spec.initContainers
content:
name: terraform-init
any: true
template: rp/deployment.yaml

- it: should include terraform config in applications-rp configmap
asserts:
- matchRegex:
path: data["radius-self-host.yaml"]
pattern: "terraform:\\s+path: \"/terraform\""
template: rp/configmaps.yaml

# dynamic-rp terraform volume tests
- it: should use PVC for terraform volume in dynamic-rp when terraform is enabled
set:
global.terraform.enabled: true
dynamicrp.image: dynamic-rp
dynamicrp.tag: latest
asserts:
- contains:
path: spec.template.spec.volumes
content:
name: terraform
persistentVolumeClaim:
claimName: terraform-storage
template: dynamic-rp/deployment.yaml

- it: should mount terraform volume in dynamic-rp container
set:
global.terraform.enabled: true
dynamicrp.image: dynamic-rp
dynamicrp.tag: latest
dynamicrp.terraform.path: /terraform
asserts:
- contains:
path: spec.template.spec.containers[0].volumeMounts
content:
name: terraform
mountPath: /terraform
template: dynamic-rp/deployment.yaml

- it: should include terraform init container in dynamic-rp when terraform is enabled
set:
global.terraform.enabled: true
dynamicrp.image: dynamic-rp
dynamicrp.tag: latest
asserts:
- isNotEmpty:
path: spec.template.spec.initContainers
template: dynamic-rp/deployment.yaml
- contains:
path: spec.template.spec.initContainers
content:
name: terraform-init
any: true
template: dynamic-rp/deployment.yaml

# Both deployments use the same shared PVC
- it: should use shared PVC for both deployments
set:
global.terraform.enabled: true
rp.image: applications-rp
rp.tag: latest
dynamicrp.image: dynamic-rp
dynamicrp.tag: latest
asserts:
# applications-rp uses shared PVC
- contains:
path: spec.template.spec.volumes
content:
name: terraform
persistentVolumeClaim:
claimName: terraform-storage
template: rp/deployment.yaml
# dynamic-rp uses same shared PVC
- contains:
path: spec.template.spec.volumes
content:
name: terraform
persistentVolumeClaim:
claimName: terraform-storage
template: dynamic-rp/deployment.yaml
7 changes: 7 additions & 0 deletions deploy/Chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ global:
# Valid values: TRACE, DEBUG, INFO, WARN, ERROR, OFF
# Default: ERROR
loglevel: "ERROR"
# Storage size for shared terraform PVC (used by UCP installer and recipe execution)
# This PVC stores installed Terraform versions managed via `rad terraform install`
storageSize: "1Gi"
# Storage class name for the terraform PVC
# Leave empty to use the default storage class
# For ReadWriteMany access, use a storage class that supports it (e.g., NFS, EFS, Azure Files)
storageClassName: ""

controller:
image: controller
Expand Down
Loading
Loading