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
109 changes: 102 additions & 7 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: ci
name: CI

on:
push:
Expand All @@ -22,14 +22,109 @@ jobs:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build images
uses: hiberbee/github-action-skaffold@1.19.0
- name: Setup Skaffold
uses: heypigeonhq/setup-skaffold@v1.0.0
with:
skaffold-version: 2.14.1
command: build
file-output: build/images.json
version: 2.14.1
- name: Build images
run: |
mkdir build
skaffold build --file-output=build/images.json
- name: Archive image tags
uses: actions/upload-artifact@v4
with:
name: images
path: build/images.json
path: build/images.json

verify:
name: Verify
runs-on: ubuntu-latest
env:
CODECOV_FILE: build/coverage.xml
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
- name: Generate
run: make generate format
- name: No changed files
run: git diff --name-status --exit-code
- name: Lint
run: make lint
- name: Integration test
run: make integration-test coverage
- name: Generate
uses: irongut/[email protected]
with:
filename: build/coverage.xml,build/coverage.e2e.xml
badge: true
format: markdown
output: both
- name: Archive coverage report
uses: actions/upload-artifact@v4
with:
name: coverage
path: ${{ env.CODECOV_FILE }}

# e2e:
# name: E2E Test
# needs:
# - verify
# - image-build
# runs-on: ubuntu-latest
# env:
# CODECOV_FILE: build/coverage.e2e.xml
# SKAFFOLD_NAMESPACE: sandbox
# SKAFFOLD_RUN_ID: e2e-test
# steps:
# - name: Checkout
# uses: actions/checkout@v4
# - name: Setup Skaffold
# uses: heypigeonhq/[email protected]
# with:
# version: 2.14.1
# - name: Create Kind cluster
# uses: helm/kind-action@v1
# with:
# cluster_name: kind-etcd
# - name: Bootstrap
# run: |
# kustomize build --enable-helm config/bootstrap | kubectl apply -f -
# kubectl --namespace cert-manager wait --for=condition=Available deployment/cert-manager-webhook
# kubectl get namespace sandbox 2>/dev/null || kubectl create namespace sandbox
# - name: Build images
# run: |
# mkdir build
# skaffold build --file-output=build/images.json
# - name: Deploy
# run: skaffold deploy --profile e2e --build-artifacts=build/images.json
# - name: Run E2E tests
# run: skaffold verify --namespace sandbox --build-artifacts=build/images.json
# - name: Fetch coverage
# run: make fetch-coverage
# - name: Archive coverage report
# uses: actions/upload-artifact@v4
# with:
# name: coverage-e2e
# path: ${{ env.CODECOV_FILE }}

# coverage:
# name: Coverage Report
# needs:
# - verify
# - e2e
# runs-on: ubuntu-latest
# steps:
# - name: Download coverage report
# uses: actions/download-artifact@v4
# with:
# name: coverage
# path: build
# - name: Download E2E coverage report
# uses: actions/download-artifact@v4
# with:
# name: coverage-e2e
# path: build
15 changes: 15 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: "2"
run:
concurrency: 4
modules-download-mode: readonly
tests: true
linters:
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 0
max-same-issues: 0
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 Agoda Company Pte Ltd.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ SKAFFOLD_NAMESPACE ?= fleet
GOCOVERPKG := github.com/agoda-com/etcd-operator/pkg/...
GOTESTARGS := -test.timeout=30m
GOMUTESTARGS := ./pkg
GOLANGCILINT_VERSION := v1.64.8
GOLANGCILINT_VERSION := v2.0.2

include makefiles/go.mk
include makefiles/controller.mk
Expand Down
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# ETCD Operator

![Code Coverage](https://img.shields.io/badge/Code%20Coverage-26%25-critical?style=flat)

## Docs

* [API](/docs/api.md)
Expand All @@ -15,8 +17,8 @@
* [config/rbac](config/rbac) - cluster-wide RBAC

## Profiles
* [config/sandbox](config/sandbox) - single namespace deployment with namespace-scoped RBAC
* [config/e2e](config/e2e) - sandbox with coverage enabled on etcd-operator
* [default](config/default) - default deployment
* [config/e2e](config/e2e) - e2e rbac sandbox with coverage enabled on etcd-operator

## Running locally

Expand All @@ -28,7 +30,14 @@ Operator requires cert-manager and CRDs to be installed in the cluster.
kustomize build --enable-helm config/bootstrap | kubectl apply -f -
```

### Run
### Deploy (docker+kubectl)

```
docker build --tag ghcr.io/agoda-com/etcd .
kubectl apply -k config/default
```

### Deploy (skaffold)

```
skaffold run
Expand Down Expand Up @@ -74,11 +83,6 @@ End-to-end tests:
make e2e-test
```

Run end-to-end tests on dev cluster:
```sh
make e2e-test
```

Coverage:
```sh
make test coverage
Expand Down
5 changes: 3 additions & 2 deletions config/default/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: default
namespace: etcd
resources:
- ../rbac
- ../base
- ../base
- namespace.yaml
3 changes: 3 additions & 0 deletions config/default/namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Namespace
metadata:
name: etcd
4 changes: 2 additions & 2 deletions e2e/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestBackup(t *testing.T) {

// create some data
k, v := "leela", "turanga"
if _, err := ecl.KV.Put(ctx, k, v); err != nil {
if _, err := ecl.Put(ctx, k, v); err != nil {
t.Fatal("failed to put key:", err)
}

Expand All @@ -55,7 +55,7 @@ func TestBackup(t *testing.T) {
triggerCronJob(t, ctx, kcl, key, 5*time.Minute)

// delete data
if _, err := ecl.KV.Delete(ctx, k); err != nil {
if _, err := ecl.Delete(ctx, k); err != nil {
t.Fatal("failed to delete key:", err)
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/cluster/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,8 @@ func (r *Reconciler) ReconcileStatus(ctx context.Context, cluster *apiv1.EtcdClu
return
}

switch {
case resp.Leader == resp.Header.MemberId:
switch resp.Leader {
case resp.Header.MemberId:
status.Role = apiv1.MemberRoleLeader
default:
status.Role = apiv1.MemberRoleMember
Expand Down
25 changes: 3 additions & 22 deletions pkg/resources/pki.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
cmv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

type CertificateBuilder struct{ *cmv1.Certificate }
Expand Down Expand Up @@ -105,38 +104,20 @@ func (c CertificateBuilder) Subject(cn string, orgs ...string) CertificateBuilde
return c
}

func (c CertificateBuilder) SecretLabel(key, value string) CertificateBuilder {
func (c CertificateBuilder) SecretLabels(labels map[string]string) CertificateBuilder {
if c.Spec.SecretTemplate == nil {
c.Spec.SecretTemplate = &cmv1.CertificateSecretTemplate{}
}

if c.Spec.SecretTemplate.Labels == nil {
c.Spec.SecretTemplate.Labels = make(map[string]string)
}

c.Spec.SecretTemplate.Labels[key] = value
return c
}

func (c CertificateBuilder) SecretLabels(labels map[string]string) CertificateBuilder {
if c.Spec.SecretTemplate == nil {
c.Spec.SecretTemplate = &cmv1.CertificateSecretTemplate{}
c.Spec.SecretTemplate.Labels = map[string]string{}
}

switch {
case c.Spec.SecretTemplate.Labels == nil:
c.Spec.SecretTemplate.Labels = labels
default:
maps.Copy(c.Spec.SecretTemplate.Labels, labels)
}
maps.Copy(c.Spec.SecretTemplate.Labels, labels)

return c
}

func (c CertificateBuilder) Key() client.ObjectKey {
return client.ObjectKeyFromObject(c.Certificate)
}

func (b *Builder) Certificate(names ...string) CertificateBuilder {
name := b.name(names)
cert := &cmv1.Certificate{
Expand Down
5 changes: 0 additions & 5 deletions skaffold.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@ manifests:
paths:
- config/default
profiles:
- name: fleet
manifests:
kustomize:
paths:
- config/fleet
- name: e2e
build:
artifacts:
Expand Down