Skip to content

Commit e089d70

Browse files
DanNiEShclaude
andauthored
Add HostLease controller for bare metal management via Ironic (#1)
* Add Kubebuilder scaffolding for OpenStack host management operator Sets up the foundation for a Kubernetes operator using controller-runtime v0.21.0, including RBAC configurations, metrics server, webhooks support, CI/CD workflows, and e2e testing infrastructure. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Add HostLease controller with Ironic power management Implement a controller that watches HostLease CR (from osac-operator) and reconciles spec.poweredOn to Ironic power on/off. Filters on spec.hostClass == "openstack" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 8619c72 commit e089d70

49 files changed

Lines changed: 4319 additions & 6 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
2+
# Ignore build and test binaries.
3+
bin/

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/internal/api/** linguist-generated=true

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,14 @@ updates:
77
schedule:
88
# Check for updates to GitHub Actions every week
99
interval: "weekly"
10+
- package-ecosystem: "gomod"
11+
directory: "/"
12+
schedule:
13+
# Check for updates to Go modules every week
14+
interval: "weekly"
15+
groups:
16+
go-dependencies:
17+
patterns:
18+
- "*"
19+
commit-message:
20+
prefix: "NO-ISSUE"

.github/workflows/build-image.yaml

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
name: Build container image
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
push:
7+
branches:
8+
- main
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
12+
cancel-in-progress: true
13+
14+
env:
15+
# Use docker.io for Docker Hub if empty
16+
REGISTRY: ghcr.io
17+
# github.repository as <account>/<repo>
18+
IMAGE_NAME: ${{ github.repository }}
19+
20+
21+
jobs:
22+
test:
23+
name: Run Tests
24+
runs-on: ubuntu-latest
25+
steps:
26+
- name: Checkout repository
27+
uses: actions/checkout@v6
28+
29+
- name: Set up Go
30+
uses: actions/setup-go@v6
31+
with:
32+
go-version-file: 'go.mod'
33+
34+
- name: Install kind
35+
uses: helm/kind-action@v1
36+
with:
37+
install_only: true
38+
39+
- name: Run all tests
40+
run: make test
41+
42+
build:
43+
needs: test
44+
runs-on: ubuntu-latest
45+
permissions:
46+
contents: read
47+
packages: write
48+
49+
steps:
50+
- name: Checkout repository
51+
uses: actions/checkout@v6
52+
53+
# Login against a Docker registry except on PR
54+
# https://github.com/docker/login-action
55+
- name: Log into registry ${{ env.REGISTRY }}
56+
if: github.event_name != 'pull_request'
57+
uses: docker/login-action@v4
58+
with:
59+
registry: ${{ env.REGISTRY }}
60+
username: ${{ github.actor }}
61+
password: ${{ secrets.GITHUB_TOKEN }}
62+
63+
# Extract metadata (tags, labels) for Docker
64+
# https://github.com/docker/metadata-action
65+
- name: Extract Docker metadata
66+
id: meta
67+
uses: docker/metadata-action@v6
68+
with:
69+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
70+
tags: |
71+
type=semver,pattern=v{{version}}
72+
type=semver,pattern=v{{major}}.{{minor}}
73+
type=semver,pattern=v{{major}}
74+
type=ref,event=branch
75+
type=ref,event=pr
76+
type=ref,event=tag
77+
type=sha
78+
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
79+
80+
81+
# Build and push Docker image with Buildx (don't push on PR)
82+
# https://github.com/docker/build-push-action
83+
- name: Build and push Docker image
84+
id: build-operator
85+
uses: docker/build-push-action@v7
86+
with:
87+
context: .
88+
file: Containerfile
89+
push: ${{ github.event_name != 'pull_request' }}
90+
tags: ${{ steps.meta.outputs.tags }}
91+
labels: ${{ steps.meta.outputs.labels }}
92+
93+
# Extract the commit SHA tag for manifest generation
94+
- name: Extract commit SHA tag
95+
id: sha-tag
96+
if: github.event_name != 'pull_request'
97+
run: |
98+
# Extract the sha tag from the metadata output
99+
FULL_SHA_TAG=$(echo "${{ steps.meta.outputs.tags }}" | grep -E "sha-[0-9a-f]{7}" | head -n1)
100+
SHA_TAG=$(echo "$FULL_SHA_TAG" | sed "s/.*://")
101+
echo "sha-tag=$SHA_TAG" >> $GITHUB_OUTPUT
102+
echo "full-sha-tag=$FULL_SHA_TAG" >> $GITHUB_OUTPUT
103+
echo "manifest-tag=$SHA_TAG-manifests" >> $GITHUB_OUTPUT
104+
echo "Using SHA tag: $SHA_TAG"
105+
echo "Full SHA tag: $FULL_SHA_TAG"
106+
echo "Manifest tag: $SHA_TAG-manifests"
107+
108+
# Set up Go for kustomize operations
109+
- name: Set up Go for manifest generation
110+
if: github.event_name != 'pull_request'
111+
uses: actions/setup-go@v6
112+
with:
113+
go-version-file: 'go.mod'
114+
115+
# Generate manifests with kustomize pointing to the SHA-tagged image
116+
- name: Generate manifests with kustomize
117+
if: github.event_name != 'pull_request'
118+
run: |
119+
# Install kustomize
120+
make kustomize
121+
122+
# Create dist directory
123+
mkdir -p dist
124+
125+
# Set the manager image to the SHA-tagged version
126+
cd config/manager && ../../bin/kustomize edit set image controller=${{ steps.sha-tag.outputs.full-sha-tag }}
127+
128+
# Generate the complete manifest
129+
cd ../..
130+
./bin/kustomize build config/default > dist/install.yaml
131+
132+
echo "Generated manifest with image: ${{ steps.sha-tag.outputs.full-sha-tag }}"
133+
echo "Manifest content preview:"
134+
head -20 dist/install.yaml
135+
136+
# Create Dockerfile for manifest container
137+
- name: Create manifest container Dockerfile
138+
if: github.event_name != 'pull_request'
139+
run: |
140+
cat > Dockerfile.manifests << 'EOF'
141+
FROM scratch
142+
COPY dist/install.yaml /manifests/install.yaml
143+
EOF
144+
145+
echo "Created Dockerfile.manifests:"
146+
cat Dockerfile.manifests
147+
148+
# Extract metadata for manifest container
149+
- name: Extract manifest container metadata
150+
id: meta-manifests
151+
if: github.event_name != 'pull_request'
152+
uses: docker/metadata-action@v6
153+
with:
154+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
155+
tags: |
156+
type=raw,value=${{ steps.sha-tag.outputs.manifest-tag }}
157+
158+
# Build and push manifest container
159+
- name: Build and push manifest container
160+
if: github.event_name != 'pull_request'
161+
uses: docker/build-push-action@v7
162+
with:
163+
context: .
164+
file: Dockerfile.manifests
165+
push: true
166+
tags: ${{ steps.meta-manifests.outputs.tags }}
167+
labels: ${{ steps.meta-manifests.outputs.labels }}

.github/workflows/pre-commit.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,16 @@ jobs:
1212
with:
1313
python-version: "3.13"
1414
- uses: pre-commit/action@v3.0.1
15+
with:
16+
extra_args: -c .pre-commit-config-ci.yaml
17+
18+
golangci-lint:
19+
name: lint
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v6
23+
- uses: actions/setup-go@v6
24+
with:
25+
go-version: stable
26+
- name: golangci-lint
27+
uses: golangci/golangci-lint-action@v9

.gitignore

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Binaries for programs and plugins
2+
*.exe
3+
*.exe~
4+
*.dll
5+
*.so
6+
*.dylib
7+
bin/*
8+
main
9+
Dockerfile.cross
10+
Dockerfile.manifests
11+
dist/
12+
13+
# Test binary, built with `go test -c`
14+
*.test
15+
16+
# Output of the go coverage tool, specifically when used with LiteIDE
17+
*.out
18+
19+
# Go workspace file
20+
go.work
21+
22+
# Kubernetes Generated files - skip generated files, except for vendored files
23+
!vendor/**/zz_generated.*
24+
25+
# editor and IDE paraphernalia
26+
.idea
27+
.vscode
28+
*.swp
29+
*.swo
30+
*~
31+
32+
# Development memory/notes (local only)
33+
MEMORY.md
34+
35+
# Claude notes
36+
CLAUDE.md

.golangci.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
version: "2"
2+
run:
3+
allow-parallel-runners: true
4+
linters:
5+
default: none
6+
enable:
7+
- dupl
8+
- errcheck
9+
- ginkgolinter
10+
- goconst
11+
- gocyclo
12+
- govet
13+
- ineffassign
14+
- lll
15+
- misspell
16+
# nakedret
17+
- prealloc
18+
- revive
19+
- staticcheck
20+
- unconvert
21+
# unparam
22+
- unused
23+
settings:
24+
revive:
25+
rules:
26+
- name: comment-spacings
27+
staticcheck:
28+
checks:
29+
- all
30+
- '-QF1008'
31+
exclusions:
32+
generated: lax
33+
rules:
34+
- linters:
35+
- lll
36+
path: api/*
37+
- linters:
38+
- dupl
39+
- lll
40+
path: internal/*
41+
- linters:
42+
- dupl
43+
path: api/v1alpha1/clusterorder_clusterreference.go
44+
- linters:
45+
- dupl
46+
path: api/v1alpha1/computeinstance_virtualmachinereference.go
47+
paths:
48+
- third_party$
49+
- builtin$
50+
- examples$
51+
formatters:
52+
enable:
53+
- gofmt
54+
- goimports
55+
exclusions:
56+
generated: lax
57+
paths:
58+
- third_party$
59+
- builtin$
60+
- examples$

.pre-commit-config-ci.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v5.0.0
4+
hooks:
5+
- id: trailing-whitespace
6+
- id: check-merge-conflict
7+
- id: end-of-file-fixer
8+
- id: check-added-large-files
9+
- id: check-case-conflict
10+
- id: check-json
11+
- id: check-symlinks
12+
- id: detect-private-key
13+
14+
- repo: https://github.com/adrienverge/yamllint.git
15+
rev: v1.35.1
16+
hooks:
17+
- id: yamllint
18+
exclude: "^config/"
19+
files: \.(yaml|yml)$
20+
types: [file, yaml]
21+
entry: yamllint --strict

.pre-commit-config.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ repos:
1515
rev: v1.35.1
1616
hooks:
1717
- id: yamllint
18+
exclude: "^config/"
1819
files: \.(yaml|yml)$
1920
types: [file, yaml]
2021
entry: yamllint --strict
22+
23+
- repo: local
24+
hooks:
25+
- id: golangci-lint
26+
pass_filenames: false
27+
name: golangci-lint
28+
language: system
29+
files: \.go$
30+
entry: bin/golangci-lint run --fix

Containerfile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Build the manager binary
2+
FROM golang:1.25 AS builder
3+
ARG TARGETOS
4+
ARG TARGETARCH
5+
6+
WORKDIR /workspace
7+
# Copy the Go Modules manifests
8+
COPY go.mod go.mod
9+
COPY go.sum go.sum
10+
# cache deps before building and copying source so that we don't need to re-download as much
11+
# and so that source changes don't invalidate our downloaded layer
12+
RUN go mod download
13+
14+
# Copy the go source
15+
COPY . ./
16+
17+
# Build
18+
# the GOARCH has not a default value to allow the binary be built according to the host where the command
19+
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
20+
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
21+
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
22+
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
23+
24+
# Use distroless as minimal base image to package the manager binary
25+
# Refer to https://github.com/GoogleContainerTools/distroless for more details
26+
FROM gcr.io/distroless/static:nonroot
27+
WORKDIR /
28+
COPY --from=builder /workspace/manager .
29+
USER 65532:65532
30+
31+
ENTRYPOINT ["/manager"]

0 commit comments

Comments
 (0)