Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/dependabot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ updates:
schedule:
interval: "weekly"
- package-ecosystem: "docker"
directory: "/dp-terraform/helm"
directory: "/fleetshard-operator"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
Expand Down
1 change: 0 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
- [ ] Add secret to app-interface Vault or Secrets Manager if necessary
- [ ] RDS changes were e2e tested [manually](../docs/development/howto-e2e-test-rds.md)
- [ ] Check AWS limits are reasonable for changes provisioning new resources
- [ ] (If applicable) Changes to the dp-terraform Helm values have been reflected in the addon on integration environment

## Test manual

Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/aws-integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ on:
- 'docs/**'
- 'pkg/api/openapi/docs/**'
- 'pkg/api/openapi/.openapi-generator-ignore'
- 'dp-terraform/**'
- 'deploy/**'
- '.design-proposals/**'

pull_request:
Expand All @@ -34,6 +36,7 @@ on:
- 'pkg/api/openapi/docs/**'
- 'pkg/api/openapi/.openapi-generator-ignore'
- 'dp-terraform/**'
- 'deploy/**'
- '.design-proposals/**'

jobs:
Expand Down
37 changes: 30 additions & 7 deletions .github/workflows/multicluster-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ on:
- 'internal/central/pkg/handlers/admin_central.go'
- 'internal/central/pkg/services/central.go'

# Cancel previous runs
# see: https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true

jobs:
create-cluster:
name: "Create Test Infra Clusters"
Expand All @@ -33,16 +39,29 @@ jobs:
strategy:
matrix:
name: [acscs1, acscs2]
outputs:
cluster_id: ${{ steps.cluster_id.outputs.short_sha }}
steps:
- name: Generate cluster ID
id: cluster_id
run: |
# OSD cluster names are limited to 15 characters.
# Use first 7 chars of commit SHA for traceability and uniqueness.
# Format: <prefix>-<7-char-sha> (e.g., acscs1-a1b2c3d = 14 chars)
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
echo "short_sha=$SHORT_SHA" >> "$GITHUB_OUTPUT"

- name: Create cluster
uses: stackrox/actions/infra/create-cluster@v1
with:
token: ${{ secrets.INFRA_TOKEN }}
flavor: osd-on-aws
name: ${{ matrix.name }}-${{ github.run_id }}${{ github.run_attempt }}
flavor: rosahcp
name: ${{ matrix.name }}-${{ steps.cluster_id.outputs.short_sha }}
description: "Used for acs-fleet-manager Multicluster E2E tests. Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
lifespan: 3h
args: nodes=3,machine-type=m5.2xlarge
wait: true
no-slack: true

e2e-test:
name: "Multicluster e2e tests"
Expand All @@ -66,13 +85,14 @@ jobs:
- name: Set cluster credentials
run: |
set -eo pipefail
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
mkdir kube
cluster1Conf="$(pwd)/kube/cluster1"
url=$(infractl artifacts "acscs1-${{ github.run_id }}${{ github.run_attempt }}" --json | jq '.Artifacts[] | select(.Name=="kubeconfig") | .URL' -r)
url=$(infractl artifacts "acscs1-${SHORT_SHA}" --json | jq '.Artifacts[] | select(.Name=="kubeconfig") | .URL' -r)
wget -O "$cluster1Conf" "$url"

cluster2Conf="$(pwd)/kube/cluster2"
url=$(infractl artifacts "acscs2-${{ github.run_id }}${{ github.run_attempt }}" --json | jq '.Artifacts[] | select(.Name=="kubeconfig") | .URL' -r)
url=$(infractl artifacts "acscs2-${SHORT_SHA}" --json | jq '.Artifacts[] | select(.Name=="kubeconfig") | .URL' -r)
wget -O "$cluster2Conf" "$url"

echo "CLUSTER_1_KUBECONFIG=$cluster1Conf" >> "$GITHUB_ENV"
Expand Down Expand Up @@ -102,7 +122,9 @@ jobs:
name: "Cleanup Test Infra Clusters"
runs-on: ubuntu-latest
needs: [create-cluster, e2e-test]
if: ${{ !github.event.pull_request.head.repo.fork && !github.event.pull_request.draft && always() }} # do not run for PRs from forks
# do not run for PRs from forks
# keep the clusters in case of failure for debugging
if: ${{ !github.event.pull_request.head.repo.fork && !github.event.pull_request.draft && (success() || cancelled()) }}
environment: development
env:
INFRA_TOKEN: ${{ secrets.INFRA_TOKEN }}
Expand All @@ -112,6 +134,7 @@ jobs:
- name: Delete test clusters
run: |
set -o pipefail
infractl delete "acscs1-${{ github.run_id }}${{ github.run_attempt }}"
infractl delete "acscs2-${{ github.run_id }}${{ github.run_attempt }}"
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
infractl delete "acscs1-${SHORT_SHA}"
infractl delete "acscs2-${SHORT_SHA}"
exit 0
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -895,3 +895,18 @@ CLUSTER_ID ?= test
run/emailsender:
@CLUSTER_ID=$(CLUSTER_ID) go run emailsender/cmd/app/main.go
.PHONY: run/emailsender

deploy/emailsender: IMAGE_REPO?="$(external_image_registry)/$(emailsender_image_repository)"
deploy/emailsender: IMAGE_TAG?="$(image_tag)"
deploy/emailsender:
@kubectl apply -n "$(NAMESPACE)" -f "dev/env/manifests/emailsender-db"
@helm upgrade --install -n "$(NAMESPACE)" emailsender "deploy/charts/emailsender" \
--values "dev/env/values/emailsender/values.yaml" \
--set image.repo="$(IMAGE_REPO)" \
--set image.tag="$(IMAGE_TAG)"
.PHONY: deploy/emailsender

undeploy/emailsender:
@helm uninstall -n "$(NAMESPACE)" emailsender
@kubectl delete -n "$(NAMESPACE)" -f "dev/env/manifests/emailsender-db"
.PHONY: undeploy/emailsender
23 changes: 23 additions & 0 deletions deploy/charts/emailsender/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 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/
24 changes: 24 additions & 0 deletions deploy/charts/emailsender/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: v2
name: emailsender
description: "Chart to deploy emailsender service for RHACS dataplane clusters"

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: "0.1.0"

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.1.0"
57 changes: 57 additions & 0 deletions deploy/charts/emailsender/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Emailsender Helm Chart

This Helm chart deploys the emailsender service for RHACS dataplane clusters.

## Overview

The emailsender service handles email notifications for RHACS tenants. It uses AWS SES as the email provider and requires a PostgreSQL database for storing email records.

## Prerequisites

- Kubernetes cluster with OpenShift service-ca operator (for HTTPS support)
- External Secrets Operator (for AWS secrets management)
- AWS IAM role for SES access

## Configuration

See [values.yaml](values.yaml) for the full list of configuration options.

### Key Configuration Values

- `replicas`: Number of replicas (default: 3)
- `image.repo`: Container image repository
- `image.tag`: Container image tag
- `clusterId`: Data plane cluster ID
- `clusterName`: Data plane cluster name
- `environment`: Environment name (e.g., "production", "staging")
- `senderAddress`: Email sender address
- `emailProvider`: Email provider (default: "AWS_SES")
- `aws.region`: AWS region for SES

## Installation

```bash
helm install emailsender ./deploy/charts/emailsender \
--set clusterId=my-cluster \
--set clusterName=my-cluster \
--set environment=production \
--set aws.region=us-east-1
```

## Components

The chart deploys:

1. **Deployment**: The emailsender service with 3 replicas by default
2. **Service**: ClusterIP service exposing port 443 (HTTPS)
3. **ServiceAccount**: For AWS IAM role integration
4. **RBAC**: ClusterRole and ClusterRoleBinding
5. **ExternalSecrets**: For database credentials and AWS role ARN

## Database

The emailsender requires a PostgreSQL database. Database credentials are managed via External Secrets Operator and stored in AWS Secrets Manager.

## HTTPS/TLS

The service uses OpenShift's service-ca operator to generate TLS certificates. This can be disabled by setting `enableHTTPS=false` for clusters without the service-ca operator.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{{- if .Values.emailsender.enabled }}
apiVersion: v1
kind: ServiceAccount
metadata:
Expand All @@ -22,4 +21,3 @@ apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: emailsender-role
{{- end }}
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
{{- if and (.Capabilities.APIVersions.Has "external-secrets.io/v1beta1") .Values.global.createExternalSecrets }}
{{- if and (.Capabilities.APIVersions.Has "external-secrets.io/v1beta1") .Values.createExternalSecrets }}
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: emailsender-db-secret
namespace: {{ .Release.Namespace }}
spec:
secretStoreRef:
name: {{ .Values.global.secretStore.aws.secretsManagerSecretStoreName }}
name: {{ .Values.secretStore.aws.secretsManagerSecretStoreName }}
kind: ClusterSecretStore
target:
name: emailsender-db
creationPolicy: Owner
data:
- secretKey: db.user # pragma: allowlist secret
remoteRef:
key: "cluster-{{ .Values.emailsender.clusterName }}-emailsender-db"
key: "cluster-{{ .Values.clusterName }}-emailsender-db"
property: "username"
- secretKey: db.name # pragma: allowlist secret
remoteRef:
key: "cluster-{{ .Values.emailsender.clusterName }}-emailsender-db"
key: "cluster-{{ .Values.clusterName }}-emailsender-db"
property: "databaseName"
- secretKey: db.host # pragma: allowlist secret
remoteRef:
key: "cluster-{{ .Values.emailsender.clusterName }}-emailsender-db"
key: "cluster-{{ .Values.clusterName }}-emailsender-db"
property: "host"
- secretKey: db.password # pragma: allowlist secret
remoteRef:
key: "cluster-{{ .Values.emailsender.clusterName }}-emailsender-db"
key: "cluster-{{ .Values.clusterName }}-emailsender-db"
property: "password" # pragma: allowlist secret
- secretKey: db.port # pragma: allowlist secret
remoteRef:
key: "cluster-{{ .Values.emailsender.clusterName }}-emailsender-db"
key: "cluster-{{ .Values.clusterName }}-emailsender-db"
property: "port"
---
apiVersion: external-secrets.io/v1beta1
Expand All @@ -40,7 +40,7 @@ metadata:
namespace: {{ .Release.Namespace }}
spec:
secretStoreRef:
name: {{ .Values.global.secretStore.aws.parameterStoreSecretStoreName }}
name: {{ .Values.secretStore.aws.parameterStoreSecretStoreName }}
kind: ClusterSecretStore
target:
name: emailsender-parameters
Expand Down
Loading
Loading