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: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@
/report.html
/shell.nix
/testing/

bin/
18 changes: 18 additions & 0 deletions .github/workflows/push-charts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,21 @@ jobs:
CHART_PACKAGE=$(ls $CHART_DIR/*.tgz)
helm push $CHART_PACKAGE oci://${{ env.REGISTRY }}/${{ github.repository }}/charts/
done
- name: Get all changed reservations Chart.yaml files
id: changed-chart-yaml-files-reservations
uses: tj-actions/changed-files@v46
with:
files: |
reservations/dist/chart/Chart.yaml
- name: Push reservations charts to registry
if: steps.changed-chart-yaml-files-reservations.outputs.all_changed_files != ''
shell: bash
env:
ALL_CHANGED_FILES: ${{ steps.changed-chart-yaml-files-reservations.outputs.all_changed_files }}
run: |
for CHART_FILE in ${ALL_CHANGED_FILES}; do
CHART_DIR=$(dirname $CHART_FILE)
helm package $CHART_DIR --dependency-update --destination $CHART_DIR
CHART_PACKAGE=$(ls $CHART_DIR/*.tgz)
helm push $CHART_PACKAGE oci://${{ env.REGISTRY }}/${{ github.repository }}/charts/
done
41 changes: 41 additions & 0 deletions .github/workflows/push-images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,44 @@ jobs:
subject-name: ${{ env.REGISTRY }}/${{ github.repository }}
subject-digest: ${{ steps.push_cortex.outputs.digest }}
push-to-registry: true
# Only build and push the reservations operator image if there are changes
# in the reservations directory.
- name: Get all changed reservations/ files
id: changed_reservations_files
uses: tj-actions/changed-files@v46
with:
files: |
reservations/**
- name: Docker Meta (Cortex Reservations)
if: steps.changed_reservations_files.outputs.all_changed_files != ''
id: meta_cortex_reservations
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}-reservations-operator
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
latest
- name: Build and Push Cortex Reservations Operator
if: steps.changed_reservations_files.outputs.all_changed_files != ''
id: push_cortex_reservations
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile.kubebuilder
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta_cortex_reservations.outputs.tags }}
labels: ${{ steps.meta_cortex_reservations.outputs.labels }}
build-args: |
GO_MOD_PATH=reservations
GIT_TAG=${{ github.ref_name }}
GIT_COMMIT=${{ github.sha }}
- name: Generate Artifact Attestation for Cortex Reservations
if: steps.changed_reservations_files.outputs.all_changed_files != ''
uses: actions/attest-build-provenance@v2
with:
subject-name: ${{ env.REGISTRY }}/${{ github.repository }}-reservations-operator
subject-digest: ${{ steps.push_cortex_reservations.outputs.digest }}
push-to-registry: true
70 changes: 56 additions & 14 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ jobs:
with:
go-version: 1.25.0
- name: Test quickly without Docker
run: go test -v ./...
run: |
echo "Testing main module..."
go test -v ./...
echo "Testing reservations module..."
cd reservations && go test -v ./...

test-with-docker:
# We don't need to run this longer test if the previous one already failed.
Expand All @@ -43,15 +47,27 @@ jobs:
export GITHUB_ACTIONS=1
export POSTGRES_CONTAINER=1
export RABBITMQ_CONTAINER=1

echo "Running tests for main module..."
go test -v \
-coverpkg=./internal/... \
-coverprofile=pr_profile.cov ./internal/...
go tool cover -func pr_profile.cov > pr_func_coverage.txt
- name: Upload coverage file

echo "Running tests for reservations module..."
cd reservations
go test -v \
-coverpkg=./internal/... \
-coverprofile=reservations_profile.cov ./internal/...
go tool cover -func reservations_profile.cov > reservations_func_coverage.txt
cd ..
- name: Upload coverage files
uses: actions/upload-artifact@v4
with:
name: pr-func-coverage
path: pr_func_coverage.txt
path: |
pr_func_coverage.txt
reservations/reservations_func_coverage.txt
# Steps below are only executed if the workflow is triggered by a pull request
- name: Delete old coverage comments (PR only)
if: ${{ github.event_name == 'pull_request' }}
Expand All @@ -73,7 +89,7 @@ jobs:
});
}
}
- name: Download coverage file (PR only)
- name: Download coverage files (PR only)
if: ${{ github.event_name == 'pull_request' }}
uses: actions/download-artifact@v5
with:
Expand All @@ -87,20 +103,46 @@ jobs:
const fs = require('fs');
const path = require('path');

// Extract the last line of the coverage report
const coverageReport = fs.readFileSync('pr_func_coverage.txt', 'utf8');
const lines = coverageReport.trim().split('\n');
const lastLine = lines[lines.length - 1];
const coverageMatch = lastLine.match(/total:\s+\(statements\)\s+(\d+\.\d+)%/);
const coveragePercentage = coverageMatch ? coverageMatch[1] : 'unknown';
// Read main module coverage report
const mainCoverageReport = fs.readFileSync('pr_func_coverage.txt', 'utf8');
const mainLines = mainCoverageReport.trim().split('\n');
const mainLastLine = mainLines[mainLines.length - 1];
const mainCoverageMatch = mainLastLine.match(/total:\s+\(statements\)\s+(\d+\.\d+)%/);
const mainCoveragePercentage = mainCoverageMatch ? mainCoverageMatch[1] : 'unknown';

// Read reservations module coverage report
let reservationsCoverageReport = '';
let reservationsCoveragePercentage = 'unknown';
try {
reservationsCoverageReport = fs.readFileSync('reservations/reservations_func_coverage.txt', 'utf8');
const reservationsLines = reservationsCoverageReport.trim().split('\n');
const reservationsLastLine = reservationsLines[reservationsLines.length - 1];
const reservationsCoverageMatch = reservationsLastLine.match(/total:\s+\(statements\)\s+(\d+\.\d+)%/);
reservationsCoveragePercentage = reservationsCoverageMatch ? reservationsCoverageMatch[1] : 'unknown';
} catch (error) {
reservationsCoverageReport = 'No coverage data available';
}

let commentBody = '<!-- coverage-comment -->\n';
commentBody += '## Test Coverage Report\n\n';

// Main module coverage
commentBody += '<details>\n';
commentBody += '<summary>Coverage in go module internal/: ';
commentBody += coveragePercentage;
commentBody += '<summary>Coverage in main module (internal/): ';
commentBody += mainCoveragePercentage;
commentBody += '%</summary>\n\n';
commentBody += '```text\n';
commentBody += coverageReport;
commentBody += mainCoverageReport;
commentBody += '```\n';
commentBody += '</details>\n\n';

// Reservations module coverage
commentBody += '<details>\n';
commentBody += '<summary>Coverage in reservations module (reservations/internal/): ';
commentBody += reservationsCoveragePercentage;
commentBody += '%</summary>\n\n';
commentBody += '```text\n';
commentBody += reservationsCoverageReport;
commentBody += '```\n';
commentBody += '</details>\n';

Expand All @@ -110,4 +152,4 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
body: commentBody,
});
});
14 changes: 14 additions & 0 deletions .github/workflows/update-appversion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,17 @@ jobs:
git add helm/library/cortex-postgres/Chart.yaml
git commit -m "Bump cortex-postgres chart appVersions to ${{ steps.vars.outputs.sha }} [skip ci]" || echo "No changes to commit"
git push origin HEAD:main

# Only bumped if there are changes in the reservations directory.
- name: Update appVersion in cortex-reservations Chart.yaml
if: steps.changed_reservations_files.outputs.all_changed_files != ''
run: |
sed -i 's/^\([ ]*appVersion:[ ]*\).*/\1"${{ steps.vars.outputs.sha }}"/' reservations/dist/chart/Chart.yaml
- name: Commit and push changes for cortex-reservations
if: steps.changed_reservations_files.outputs.all_changed_files != ''
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add reservations/dist/chart/Chart.yaml
git commit -m "Bump cortex-reservations chart appVersions to ${{ steps.vars.outputs.sha }} [skip ci]" || echo "No changes to commit"
git push origin HEAD:main
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ build/**
# Test binary, built with `go test -c`
*.test

bin/

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

Expand Down
31 changes: 31 additions & 0 deletions Dockerfile.kubebuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Build the manager binary
FROM golang:1.24 AS builder
ARG TARGETOS
ARG TARGETARCH
# Path of our go.mod
ARG GO_MOD_PATH=.

WORKDIR /workspace
# Copy shared cortex code
COPY . /
# Copy the Go Modules manifests
COPY ${GO_MOD_PATH} .
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532

ENTRYPOINT ["/manager"]
20 changes: 19 additions & 1 deletion Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ if not os.getenv('TILT_VALUES_PATH'):
fail("TILT_VALUES_PATH is not set.")
if not os.path.exists(os.getenv('TILT_VALUES_PATH')):
fail("TILT_VALUES_PATH "+ os.getenv('TILT_VALUES_PATH') + " does not exist.")
tilt_values = os.getenv('TILT_VALUES_PATH')

# The upgrade job may take a long time to run, so it is disabled by default.
enable_postgres_upgrade = False
Expand All @@ -22,6 +23,23 @@ helm_repo(
labels=['Repositories'],
)

def kubebuilder_binary_files(path):
"""
Return all usual binary files in a kubebuilder operator path.
Can be used to perform selective watching on code paths for docker builds.
"""
return [path + '/cmd', path + '/api', path + '/internal', path + '/go.mod', path + '/go.sum']

########### Reservations Operator & CRDs
docker_build('ghcr.io/cobaltcore-dev/cortex-reservations-operator', '.',
dockerfile='Dockerfile.kubebuilder',
build_args={'GO_MOD_PATH': 'reservations'},
only=kubebuilder_binary_files('reservations') + ['internal/', 'go.mod', 'go.sum'],
)
local('sh helm/sync.sh reservations/dist/chart')
k8s_yaml(helm('reservations/dist/chart', name='cortex-reservations', values=[tilt_values]))
k8s_resource('reservations-controller-manager', labels=['Reservations'])

########### Dev Dependencies
local('sh helm/sync.sh helm/dev/cortex-prometheus-operator')
k8s_yaml(helm('./helm/dev/cortex-prometheus-operator', name='cortex-prometheus-operator')) # Operator
Expand Down Expand Up @@ -58,9 +76,9 @@ k8s_resource('cortex-plutono', port_forwards=[
], labels=['Monitoring'])

########### Cortex Bundles
tilt_values = os.getenv('TILT_VALUES_PATH')
docker_build('ghcr.io/cobaltcore-dev/cortex', '.', only=[
'internal/', 'commands/', 'main.go', 'go.mod', 'go.sum', 'Makefile',
'reservations/api/', # API module of the reservations operator needed for the scheduler.
])
docker_build('ghcr.io/cobaltcore-dev/cortex-postgres', 'postgres')

Expand Down
24 changes: 16 additions & 8 deletions cortex.secrets.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ sharedSSOCert: &sharedSSOCert
# If true, the certificate is not verified.
selfSigned: false

# Shared keystone credentials to use.
keystone: &keystone
url: https://path-to-keystone/v3
sso: *sharedSSOCert
username: openstack-user-with-all-project-read-access
password: openstack-user-password
projectName: openstack-project-of-user
userDomainName: openstack-domain-of-user
projectDomainName: openstack-domain-of-project-scoped-to

# Custom configuration for the reservations operator.
reservations:
secrets:
keystone: *keystone

# These values will be shared across cortex-nova, cortex-manila, ... locally.
cortex-core:
secrets:
Expand All @@ -42,11 +57,4 @@ cortex-core:
sso: *sharedSSOCert
provides: [netapp_aggregate_labels_metric, netapp_node_metric]
# Override the endpoints and credentials to your OpenStack.
keystone:
url: https://path-to-keystone/v3
sso: *sharedSSOCert
username: openstack-user-with-all-project-read-access
password: openstack-user-password
projectName: openstack-project-of-user
userDomainName: openstack-domain-of-user
projectDomainName: openstack-domain-of-project-scoped-to
keystone: *keystone
Loading
Loading