Skip to content
Open
Show file tree
Hide file tree
Changes from 15 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
8 changes: 4 additions & 4 deletions Dockerfile → DockerfileAPIServer
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
go mod download

# Copy the go source
COPY main.go main.go
COPY cmd/ cmd/
COPY apis/ apis/
COPY pkg/ pkg/

Expand All @@ -39,7 +39,7 @@ COPY pkg/ pkg/
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=ssh \
CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o config-server main.go
CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o api-server cmd/api-server/main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
Expand All @@ -56,8 +56,8 @@ COPY --from=builder /etc/passwd /etc/group /etc/shadow /etc/
# add-in our ca certificates
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
#
COPY --from=builder --chown=$USERID:$USERID /workspace/config-server /app/
COPY --from=builder --chown=$USERID:$USERID /workspace/api-server /app/
WORKDIR /app
# from now on, run as the unprivileged user
USER $USERID
ENTRYPOINT ["/app/config-server"]
ENTRYPOINT ["/app/api-server"]
63 changes: 63 additions & 0 deletions DockerfileController
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copyright 2024 Nokia
# Licensed under the Apache License 2.0
# SPDX-License-Identifier: Apache-2.0

# Build the manager binary
FROM golang:1.24 AS builder
ARG TARGETOS
ARG TARGETARCH

RUN apt-get update && apt-get install -y ca-certificates git-core ssh tzdata
RUN mkdir -p -m 0700 /root/.ssh && ssh-keyscan github.com >> /root/.ssh/known_hosts
RUN git config --global url.ssh://[email protected]/.insteadOf https://github.com/

ARG USERID=10000
# add unprivileged user
RUN adduser --shell /bin/false --uid $USERID --disabled-login --home /app/ --no-create-home --gecos '' app \
&& sed -i -r "/^(app|root)/!d" /etc/group /etc/passwd \
&& sed -i -r 's#^(.*):[^:]*$#\1:/bin/false#' /etc/passwd

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# 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 --mount=type=cache,target=/root/.cache/go-build \
--mount=type=ssh \
go mod download

# Copy the go source
COPY cmd/ cmd/
COPY apis/ apis/
COPY pkg/ pkg/

# 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 --mount=type=cache,target=/root/.cache/go-build \
--mount=type=ssh \
CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o controller cmd/controller/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
FROM alpine:latest
#FROM scratch
ARG USERID=10000

RUN apk add --no-cache git ca-certificates tzdata
# add-in our timezone data file
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# add-in our unprivileged user
COPY --from=builder /etc/passwd /etc/group /etc/shadow /etc/
# add-in our ca certificates
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
#
COPY --from=builder --chown=$USERID:$USERID /workspace/controller /app/
WORKDIR /app
# from now on, run as the unprivileged user
USER $USERID
ENTRYPOINT ["/app/controller"]
25 changes: 12 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

VERSION ?= latest
REGISTRY ?= europe-docker.pkg.dev/srlinux/eu.gcr.io
PROJECT ?= config-server
IMG ?= $(REGISTRY)/${PROJECT}:$(VERSION)
IMG_SERVER ?= $(REGISTRY)/sdc-apiserver:$(VERSION)
IMG_CONTROLLER ?= $(REGISTRY)/sdc-controller:$(VERSION)

REPO = github.com/sdcio/config-server
USERID := 10000
Expand All @@ -31,24 +31,23 @@ docker:
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
ssh-add ./keys/id_rsa 2>/dev/null; true
docker build --build-arg USERID="$(USERID)" . -t ${IMG} --ssh default="$(SSH_AUTH_SOCK)"
docker build --ssh default="$(SSH_AUTH_SOCK)" --build-arg USERID="$(USERID)" \
-f DockerfileAPIServer -t ${IMG_SERVER} .
docker build --ssh default="$(SSH_AUTH_SOCK)" --build-arg USERID="$(USERID)" \
-f DockerfileController -t ${IMG_CONTROLLER} .

.PHONY: docker-push
docker-push: docker-build ## Push docker image with the manager.
docker push ${IMG}
docker push ${IMG_SERVER}
docker push ${IMG_CONTROLLER}

.PHONY: install
install: docker
kustomize build install | kubectl apply -f -
install: artifacts
kubectl apply -f artifacts/out

.PHONY: reinstall
reinstall: docker
kustomize build install | kubectl apply -f -
kubectl delete pods -n config-system --all

.PHONY: apiserver-logs
apiserver-logs:
kubectl logs -l apiserver=true --container apiserver -n config-system -f --tail 1000
reinstall: docker-push artifacts
kubectl apply -f artifacts/out

.PHONY: codegen
codegen:
Expand Down
6 changes: 5 additions & 1 deletion apis/config/config_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,18 @@ func (r *Config) IsRevertive() bool {
return true
}

func (r *Config) IsRecoverable() bool {
func (r *Config) IsRecoverable(ctx context.Context) bool {
logger := log.FromContext(ctx)
c := r.GetCondition(condition.ConditionTypeReady)
if c.Reason == string(condition.ConditionReasonUnrecoverable) {
unrecoverableMessage := &condition.UnrecoverableMessage{}
if err := json.Unmarshal([]byte(c.Message), unrecoverableMessage); err != nil {
logger.Error("is recoverable json unmarchal failed", "error", err)
return true
}
if unrecoverableMessage.ResourceVersion != r.GetResourceVersion() {
logger.Info("is recoverable resource version changed", "old/new",
fmt.Sprintf("%s/%s", unrecoverableMessage.ResourceVersion, r.GetResourceVersion()))
return true
}
return false
Expand Down
115 changes: 75 additions & 40 deletions apis/config/handlers/confighandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,75 +4,110 @@ import (
"context"
"fmt"

"github.com/henderiw/apiserver-store/pkg/storebackend"
"github.com/sdcio/config-server/apis/config"
"github.com/sdcio/config-server/pkg/target"
invv1alpha1 "github.com/sdcio/config-server/apis/inv/v1alpha1"
sdctarget "github.com/sdcio/config-server/pkg/sdc/target"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"github.com/sdcio/config-server/apis/condition"
"sigs.k8s.io/controller-runtime/pkg/client"
)


type ConfigStoreHandler struct {
Handler target.TargetHandler
Client client.Client
}

func (r *ConfigStoreHandler) DryRunCreateFn(ctx context.Context, key types.NamespacedName, obj runtime.Object, dryrun bool) (runtime.Object, error) {
accessor, err := meta.Accessor(obj)
c, target, err := r.prepareConfigAndTarget(ctx, key, obj)
if err != nil {
return obj, err
}
targetKey, err := config.GetTargetKey(accessor.GetLabels())

updates, err := sdctarget.GetIntentUpdate(ctx, storebackend.KeyFromNSN(key), c, true)
if err != nil {
return obj, err
return nil, err
}
cfg := obj.(*config.Config)
schema, warnings, err := r.Handler.SetIntent(ctx, targetKey, cfg, config.Deviation{}, dryrun)
if err != nil {
msg := fmt.Sprintf("%s err %s", warnings, err.Error())
cfg.SetConditions(condition.Failed(msg))
return cfg, err

intents := []*sdcpb.TransactionIntent{
{
Intent: sdctarget.GetGVKNSN(c),
Priority: int32(c.Spec.Priority),
Update: updates,
},
}
cfg.SetConditions(condition.ReadyWithMsg(warnings))
cfg.Status.LastKnownGoodSchema = schema
cfg.Status.AppliedConfig = &cfg.Spec
return cfg, nil

return sdctarget.RunDryRunTransaction(ctx, key, c, target, intents, dryrun)
}
func (r *ConfigStoreHandler) DryRunUpdateFn(ctx context.Context, key types.NamespacedName, obj, old runtime.Object, dryrun bool) (runtime.Object, error) {
accessor, err := meta.Accessor(obj)
c, target, err := r.prepareConfigAndTarget(ctx, key, obj)
if err != nil {
return obj, err
}
targetKey, err := config.GetTargetKey(accessor.GetLabels())

updates, err := sdctarget.GetIntentUpdate(ctx, storebackend.KeyFromNSN(key), c, true)
if err != nil {
return obj, err
return nil, err
}
cfg := obj.(*config.Config)
schema, warnings, err := r.Handler.SetIntent(ctx, targetKey, cfg, config.Deviation{}, dryrun)
if err != nil {
msg := fmt.Sprintf("%s err %s", warnings, err.Error())
cfg.SetConditions(condition.Failed(msg))
return cfg, err

intents := []*sdcpb.TransactionIntent{
{
Intent: sdctarget.GetGVKNSN(c),
Priority: int32(c.Spec.Priority),
Update: updates,
},
}
cfg.SetConditions(condition.ReadyWithMsg(warnings))
cfg.Status.LastKnownGoodSchema = schema
cfg.Status.AppliedConfig = &cfg.Spec
return cfg, nil

return sdctarget.RunDryRunTransaction(ctx, key, c, target, intents, dryrun)
}
func (r *ConfigStoreHandler) DryRunDeleteFn(ctx context.Context, key types.NamespacedName, obj runtime.Object, dryrun bool) (runtime.Object, error) {
accessor, err := meta.Accessor(obj)
c, target, err := r.prepareConfigAndTarget(ctx, key, obj)
if err != nil {
return obj, err
}
targetKey, err := config.GetTargetKey(accessor.GetLabels())
if err != nil {
return obj, err

intents := []*sdcpb.TransactionIntent{
{
Intent: sdctarget.GetGVKNSN(c),
Delete: true,
},
}
cfg := obj.(*config.Config)
warnings, err := r.Handler.DeleteIntent(ctx, targetKey, cfg, dryrun)

return sdctarget.RunDryRunTransaction(ctx, key, c, target, intents, dryrun)
}


// prepareConfigAndTarget validates labels, casts the object, fetches the Target
// and ensures it's ready.
func (r *ConfigStoreHandler) prepareConfigAndTarget(
ctx context.Context,
key types.NamespacedName,
obj runtime.Object,
) (*config.Config, *invv1alpha1.Target, error) {
accessor, err := meta.Accessor(obj)
if err != nil {
msg := fmt.Sprintf("%s err %s", warnings, err.Error())
cfg.SetConditions(condition.Failed(msg))
return cfg, err
return nil, nil, err
}
return cfg, nil
}

if _, err := config.GetTargetKey(accessor.GetLabels()); err != nil {
return nil, nil, err
}

c, ok := obj.(*config.Config)
if !ok {
return nil, nil, fmt.Errorf("expected *config.Config, got %T", obj)
}

target := &invv1alpha1.Target{}
if err := r.Client.Get(ctx, key, target); err != nil {
return nil, nil, err
}

if !target.IsReady() {
return nil, nil, fmt.Errorf("target not ready %s", key)
}

return c, target, nil
}
6 changes: 3 additions & 3 deletions artifacts/allow-apiserver-extension-traffic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
labels:
app.kubernetes.io/name: config-server
app.kubernetes.io/name: sdc-api-server
name: allow-traffic-to-apiserver-extension
namespace: network-system
namespace: sdc-system
spec:
ingress:
- from:
Expand All @@ -15,6 +15,6 @@ spec:
protocol: TCP
podSelector:
matchLabels:
app.kubernetes.io/name: config-server
app.kubernetes.io/name: sdc-api-server
policyTypes:
- Ingress
4 changes: 2 additions & 2 deletions artifacts/allow-metrics-traffic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-metrics-traffic
namespace: network-system
namespace: sdc-system
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: config-server
app.kubernetes.io/name: sdc-controller
policyTypes:
- Ingress
ingress:
Expand Down
4 changes: 2 additions & 2 deletions artifacts/apiservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ spec:
groupPriorityMinimum: 1000
versionPriority: 15
service:
name: config-server
namespace: network-system
name: api-server
namespace: sdc-system
port: 6443
version: v1alpha1
#caBundle: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURZekNDQWt1Z0F3SUJBZ0lKQUtKY0FOZ3htSG1TTUEwR0NTcUdTSWIzRFFFQkN3VUFNR1V4Q3pBSkJnTlYKQkFZVEFuVnVNUXN3Q1FZRFZRUUlEQUp6ZERFS01BZ0dBMVVFQnd3QmJERUtNQWdHQTFVRUNnd0JiekVMTUFrRwpBMVVFQ3d3Q2IzVXhKREFpQmdOVkJBTU1HMkpoYzJsakxXTmxjblJwWm1sallYUmxMV0YxZEdodmNtbDBlVEFlCkZ3MHlNakF6TXpFd09URTNOVE5hRncweU16QXpNekV3T1RFM05UTmFNR1V4Q3pBSkJnTlZCQVlUQW5WdU1Rc3cKQ1FZRFZRUUlEQUp6ZERFS01BZ0dBMVVFQnd3QmJERUtNQWdHQTFVRUNnd0JiekVMTUFrR0ExVUVDd3dDYjNVeApKREFpQmdOVkJBTU1HMkpoYzJsakxXTmxjblJwWm1sallYUmxMV0YxZEdodmNtbDBlVENDQVNJd0RRWUpLb1pJCmh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUJwMHRhNU92Vy9VcVlsR1RMZnVsam9HYkFwVnB4MW1CbUwKR0dHOUhOZmJkVWxoQ1FtMVNYK3V6dllyQ05EZEJRMWdBYWVEa1lxOWNMbnN4YU92R25peHJ1WllUV1gyaU9maQpjRTZxRUVRTm05MmxRRnBvbnBneXI2dFc3dDhkMGRNcEVVNTlYUlQzdXRGZGhHRVJUYi94clR0c1RpaUp4Vk1jCmxFSzh3ajZjLytONitHNHZEcVBydkF5cFBJaUJtbkhwVE9tbmhOdjhSeXVXc3VXVEJwb0JTMUVjbTg1VlY3MEUKUGFpYSs3bDczLzArWmFzcTBHeklCdkx4S0ZiVHVYZHh2a0REY1M5c0FuTytVcHg1YUxhbjgrR25UTWd6NzR6Vgp3WDRuSFU1blFxYkZSSC9TQzVXeGNYczJXL0JNZllBRUk2ckhnUTBKNjJiMTBSZk0vQmNDQXdFQUFhTVdNQlF3CkVnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFxUXM5eUdsalBFcUgKVHF6REpEa29DbXlTWmQ0S3VVSEpPcjY1QmhmYmppKzBsSC9Rbk9mdHdpd1FvajhwSFlnejVmZGZJa3JMTFU1KwpwMzh0cSs5QllsOFNudXd6U2EzQ2VpYUlncHUvL05xaCtieDRad1liNFJmVnZmSU5NdUZJaUhLUFBJUm1QRmlECjZJQjl0WFNrSmNmanhHd1NLRmhLSGszYU9EbmsxNUlyTDA0U040S0ZER1dncnI0WkJoL1RYT25XVmRpMHRBN3kKT2lmRkpRdWt1anhNVDRUU3ZtcmtjZW5Ubk84VEZTMk03SGVPZDRLYm14QUJFR3ZzaGZ0V2tXUGh0ZW1IYVJXYwpVOEh2SG8xS1M4cGdyYVdxMU5jMjErdHJoQS9uaGRtaWRDbW1DOHZSQ1MwU1cxZE90Q3ZJRzhpVUpIeDVKMklGCnhjUGt3aHYrN1E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
2 changes: 1 addition & 1 deletion artifacts/configmap-data-server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: data-server
namespace: network-system
namespace: sdc-system
data:
data-server.yaml: |
grpc-server:
Expand Down
11 changes: 4 additions & 7 deletions artifacts/configmap-input-vars.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: context
namespace: network-system
annotations:
kform.dev/block-type: input
kform.dev/resource-id: context ## this serves as a way to add default and manage the merge
kform.dev/default: "true"
data:
configServerImage: ghcr.io/sdcio/config-server:latest
dataServerImage: ghcr.io/sdcio/data-server:latest
sdcApiServerImage: ghcr.io/sdcio/sdc-apiserver:latest
sdcControllerImage: ghcr.io/sdcio/sdc-controller:latest
dataServerImage: ghcr.io/sdcio/data-server:v0.0.66

Loading