Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

neonvm: Add new neonvm-daemon binary skeleton #1090

Merged
merged 7 commits into from
Oct 14, 2024
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
8 changes: 6 additions & 2 deletions .github/workflows/build-test-vm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ on:

env:
IMG_POSTGRES_16_BULLSEYE: "neondatabase/vm-postgres-16-bullseye"
# using image built in the same workflow
IMG_DAEMON: "daemon:dev"
mikhail-sakhnov marked this conversation as resolved.
Show resolved Hide resolved

defaults:
run:
Expand All @@ -38,11 +40,13 @@ jobs:
tags:
outputs:
vm-postgres-16-bullseye: ${{ steps.show-tags.outputs.vm-postgres-16-bullseye }}
daemon: ${{ steps.show-tags.outputs.daemon }}
runs-on: ubuntu-latest
steps:
- id: show-tags
run: |
echo "vm-postgres-16-bullseye=${{ env.IMG_POSTGRES_16_BULLSEYE }}:${{ inputs.tag }}" | tee -a $GITHUB_OUTPUT
echo "daemon=${{ env.IMG_DAEMON }}" | tee -a $GITHUB_OUTPUT

build:
# nb: use format(..) to catch both inputs.skip = true AND inputs.skip = 'true'.
Expand All @@ -58,7 +62,7 @@ jobs:
cache: false
# Sometimes setup-go gets stuck. Without this, it'll keep going until the job gets killed
timeout-minutes: 10

- run: make docker-build-daemon
- run: make bin/vm-builder

- name: upload vm-builder
Expand All @@ -81,7 +85,7 @@ jobs:

- name: build ${{ needs.tags.outputs.vm-postgres-16-bullseye }}
run: |
./bin/vm-builder -src postgres:16-bullseye -spec tests/e2e/image-spec.yaml -dst ${{ needs.tags.outputs.vm-postgres-16-bullseye }}
./bin/vm-builder -src postgres:16-bullseye -spec tests/e2e/image-spec.yaml -dst ${{ needs.tags.outputs.vm-postgres-16-bullseye }} -daemon-image ${{ needs.tags.outputs.daemon }}
- name: docker push ${{ needs.tags.outputs.vm-postgres-16-bullseye }}
run: |
docker push ${{ needs.tags.outputs.vm-postgres-16-bullseye }}
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
IMG_CONTROLLER ?= controller:dev
IMG_VXLAN_CONTROLLER ?= vxlan-controller:dev
IMG_RUNNER ?= runner:dev
IMG_DAEMON ?= daemon:dev
IMG_SCHEDULER ?= autoscale-scheduler:dev
IMG_AUTOSCALER_AGENT ?= autoscaler-agent:dev

Expand Down Expand Up @@ -138,8 +139,7 @@ build: fmt vet bin/vm-builder ## Build all neonvm binaries.

.PHONY: bin/vm-builder
bin/vm-builder: ## Build vm-builder binary.
GOOS=linux CGO_ENABLED=0 go build -o bin/vm-builder -ldflags "-X main.Version=${GIT_INFO}" vm-builder/main.go

GOOS=linux CGO_ENABLED=0 go build -o bin/vm-builder -ldflags "-X main.Version=${GIT_INFO} -X main.NeonvmDaemonImage=${IMG_DAEMON}" vm-builder/main.go
.PHONY: run
run: fmt vet ## Run a controller from your host.
go run ./neonvm/main.go
Expand All @@ -152,7 +152,7 @@ lint: ## Run golangci-lint against code.
# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: docker-build-controller docker-build-runner docker-build-vxlan-controller docker-build-autoscaler-agent docker-build-scheduler ## Build docker images for NeonVM controllers, NeonVM runner, autoscaler-agent, scheduler
docker-build: docker-build-controller docker-build-runner docker-build-daemon docker-build-vxlan-controller docker-build-autoscaler-agent docker-build-scheduler ## Build docker images for NeonVM controllers, NeonVM runner, autoscaler-agent, scheduler

.PHONY: docker-push
docker-push: docker-build ## Push docker images to docker registry
Expand Down Expand Up @@ -187,6 +187,13 @@ docker-build-runner: docker-build-go-base ## Build docker image for NeonVM runne
--file neonvm-runner/Dockerfile \
.

.PHONY: docker-build-daemon
docker-build-daemon: ## Build docker image for NeonVM daemon.
docker build \
--tag $(IMG_DAEMON) \
--file neonvm-daemon/Dockerfile \
.

.PHONY: docker-build-vxlan-controller
docker-build-vxlan-controller: docker-build-go-base ## Build docker image for NeonVM vxlan controller
docker build \
Expand Down
10 changes: 10 additions & 0 deletions neonvm-daemon/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM golang:1.23-alpine AS builder

# Build the Go binary
COPY . .

# Build
RUN CGO_ENABLED=0 go build -o /neonvmd neonvm-daemon/main.go

FROM scratch
COPY --from=builder /neonvmd /neonvmd
67 changes: 67 additions & 0 deletions neonvm-daemon/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import (
"flag"
"fmt"
"net/http"
"os"
"time"

"go.uber.org/zap"
)

func main() {
addr := flag.String("addr", "", `address to bind for HTTP requests`)
flag.Parse()

if *addr == "" {
fmt.Println("neonvm-daemon missing -addr flag")
os.Exit(1)
}

logConfig := zap.NewProductionConfig()
logConfig.Sampling = nil // Disable sampling, which the production config enables by default.
logConfig.Level.SetLevel(zap.InfoLevel) // Only "info" level and above (i.e. not debug logs)
logger := zap.Must(logConfig.Build()).Named("neonvm-daemon")
defer logger.Sync() //nolint:errcheck // what are we gonna do, log something about it?

logger.Info("Starting neonvm-daemon", zap.String("addr", *addr))

srv := cpuServer{}
srv.run(logger, *addr)
}

type cpuServer struct{}

func (s *cpuServer) run(logger *zap.Logger, addr string) {
logger = logger.Named("cpu-srv")

mux := http.NewServeMux()
mux.HandleFunc("/cpu", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
logger.Error("unimplemented!")
w.WriteHeader(http.StatusInternalServerError)
} else if r.Method == http.MethodPut {
logger.Error("unimplemented!")
w.WriteHeader(http.StatusInternalServerError)
} else {
// unknown method
w.WriteHeader(http.StatusNotFound)
}
})

timeout := 5 * time.Second
server := http.Server{
Addr: addr,
Handler: mux,
ReadTimeout: timeout,
ReadHeaderTimeout: timeout,
WriteTimeout: timeout,
}

err := server.ListenAndServe()
if err != nil {
logger.Fatal("CPU server exited with error", zap.Error(err))
}
logger.Info("CPU server exited without error")
}
35 changes: 35 additions & 0 deletions tests/e2e/vm-neonvmd/00-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 90
commands:
- script: |
set -eux
pod="$(kubectl get neonvm -n "$NAMESPACE" example -o jsonpath='{.status.podName}')"
kubectl exec -n "$NAMESPACE" $pod -- ssh guest-vm ps aux -o comm | grep neonvmd | [ $(wc -l) -eq 1 ] || echo "neonvmd process is not found in the $pod"
---
apiVersion: vm.neon.tech/v1
mikhail-sakhnov marked this conversation as resolved.
Show resolved Hide resolved
kind: VirtualMachine
metadata:
name: example
status:
phase: Running
restartCount: 0
conditions:
- type: Available
status: "True"
cpus: 250m
memorySize: 1Gi
sshSecretName: ssh-neonvm-example
---
apiVersion: v1
kind: Secret
type: kubernetes.io/ssh-auth
immutable: true
metadata:
name: ssh-neonvm-example
ownerReferences:
- apiVersion: vm.neon.tech/v1
blockOwnerDeletion: true
controller: true
kind: VirtualMachine
name: example
24 changes: 24 additions & 0 deletions tests/e2e/vm-neonvmd/00-create-vm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
unitTest: false
---
apiVersion: vm.neon.tech/v1
kind: VirtualMachine
metadata:
name: example
spec:
schedulerName: autoscale-scheduler
enableSSH: true
guest:
cpus:
min: 0.25
use: 0.25
max: 0.25
memorySlotSize: 1Gi
memorySlots:
min: 1
use: 1
max: 1
rootDisk:
image: vm-postgres:15-bullseye
size: 1Gi
7 changes: 7 additions & 0 deletions vm-builder/files/Dockerfile.img
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ FROM {{.RootDiskImage}} AS rootdisk
USER root
{{.SpecMerge}}

FROM {{.NeonvmDaemonImage}} AS neonvm-daemon-loader

FROM alpine:3.19 AS vm-runtime
# add busybox
ENV BUSYBOX_VERSION 1.35.0
Expand All @@ -25,6 +27,8 @@ RUN set -e \
udev \
agetty \
su-exec \
util-linux-misc \
cgroup-tools \
e2fsprogs-extra \
blkid \
flock \
Expand All @@ -35,6 +39,7 @@ RUN set -e \
udevadm \
agetty \
su-exec \
cgexec \
resize2fs \
blkid \
flock \
Expand Down Expand Up @@ -65,6 +70,8 @@ RUN set -e \
quota-tools \
&& /helper.move-bins.sh quota edquota quotacheck quotaoff quotaon quotastats setquota repquota tune2fs

COPY --from=neonvm-daemon-loader /neonvmd /neonvm/bin/neonvmd

# init scripts & configs
COPY inittab /neonvm/bin/inittab
COPY vminit /neonvm/bin/vminit
Expand Down
1 change: 1 addition & 0 deletions vm-builder/files/inittab
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
::sysinit:/neonvm/bin/vminit
::once:/neonvm/bin/touch /neonvm/vmstart.allowed
::respawn:/neonvm/bin/neonvmd --addr=0.0.0.0:25183
::respawn:/neonvm/bin/udhcpc -t 1 -T 1 -A 1 -f -i eth0 -O 121 -O 119 -s /neonvm/bin/udhcpc.script
::respawn:/neonvm/bin/udevd
::wait:/neonvm/bin/udev-init.sh
Expand Down
20 changes: 19 additions & 1 deletion vm-builder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ var (
)

var (
Version string
Version string
NeonvmDaemonImage string

srcImage = flag.String("src", "", `Docker image used as source for virtual machine disk image: --src=alpine:3.19`)
dstImage = flag.String("dst", "", `Docker image with resulting disk image: --dst=vm-alpine:3.19`)
Expand All @@ -69,6 +70,8 @@ var (
quiet = flag.Bool("quiet", false, `Show less output from the docker build process`)
forcePull = flag.Bool("pull", false, `Pull src image even if already present locally`)
version = flag.Bool("version", false, `Print vm-builder version`)

daemonImageFlag = flag.String("daemon-image", "", `Specify the neonvm-daemon image: --daemon-image=neonvm-daemon:dev`)
)

func AddTemplatedFileToTar(tw *tar.Writer, tmplArgs any, filename string, tmplString string) error {
Expand Down Expand Up @@ -109,6 +112,8 @@ type TemplatesContext struct {
Env []string
RootDiskImage string

NeonvmDaemonImage string

SpecBuild string
SpecMerge string
InittabCommands []inittabCommand
Expand All @@ -130,6 +135,17 @@ func main() {
os.Exit(0)
}

if len(*daemonImageFlag) == 0 && len(NeonvmDaemonImage) == 0 {
log.Println("neonvm-daemon image not set, needs to be explicitly passed in, or compiled with -ldflags '-X main.NeonvmDaemonImage=...'")
flag.PrintDefaults()
os.Exit(1)
}

neonvmDaemonImage := NeonvmDaemonImage
if len(*daemonImageFlag) != 0 {
neonvmDaemonImage = *daemonImageFlag
}

if len(*srcImage) == 0 {
log.Println("-src not set, see usage info:")
flag.PrintDefaults()
Expand Down Expand Up @@ -270,6 +286,8 @@ func main() {
Env: imageSpec.Config.Env,
RootDiskImage: *srcImage,

NeonvmDaemonImage: neonvmDaemonImage,

SpecBuild: "", // overridden below if spec != nil
SpecMerge: "", // overridden below if spec != nil
InittabCommands: nil, // overridden below if spec != nil
Expand Down
Loading