From 25d4bfa0ee76c80cd9c546200caeebda17cca0e5 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 13:34:07 +0100 Subject: [PATCH 01/71] f-1: clean: delete keep files #1 Signed-off-by: GnomeZworc --- cmd/agent/.keep | 0 internal/.keep | 0 pkg/.keep | 0 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cmd/agent/.keep delete mode 100644 internal/.keep delete mode 100644 pkg/.keep diff --git a/cmd/agent/.keep b/cmd/agent/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/internal/.keep b/internal/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/pkg/.keep b/pkg/.keep deleted file mode 100644 index e69de29..0000000 From f67376964a6eae797a8c92c392ddb3eaa6addb69 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 14:06:02 +0100 Subject: [PATCH 02/71] f-1: scripts: start deploy script #1 Signed-off-by: GnomeZworc --- scripts/deploy.sh | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 scripts/deploy.sh diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100644 index 0000000..9fcd1dd --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -e + +SED_PARAM="" +unameOut="$(uname -s)" +case "${unameOut}" in + Linux*) SED_PARAM=" -i ";; + Darwin*) SED_PARAM=" -i '' ";; + *) exit 1 +esac + +SCRIPT_PATH="scripts/deploy.sh" + +check_latest_script () { + REMOTE_URL="${1}" + LOCAL_PATH="${2}" + + REMOTE=$(curl --silent "${REMOTE_URL}" | sha256sum) + LOCAL=$(cat ${LOCAL_PATH} | sha256sum) + + [[ "${REMOTE}" == "${LOCAL}" ]] \ + && echo "both are the same" \ + || echo "not the same" +} + +main () { + [[ -f ./libs/shflags ]] && . ./libs/shflags || eval "$(curl --silent https://git.g3e.fr/H6N/tools/raw/branch/main/libs/shflags)" + + DEFINE_boolean 'dryrun' false 'Enable dry-run mode' 'd' + DEFINE_string 'git_server' 'https://git.g3e.fr/' 'Git Server' 'g' + DEFINE_string 'repo_path' 'syonad/two/' 'Path of repository' 'r' + DEFINE_string 'branch' 'main/' 'Branch name' 'b' + + check_latest_script "${FLAGS_git_server}${FLAGS_repo_path}raw/branch/${FLAGS_branch}${SCRIPT_PATH}" "${0}" +} + +[[ "${BASH_SOURCE[0]}" == "${0}" ]] && (main "$@" || exit 1) +[[ "${BASH_SOURCE[0]}" == "" ]] && (main "$@" || exit 1) \ No newline at end of file From 05b3827e3cdd6c48c3a6ac02699904f833167fe6 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 14:09:37 +0100 Subject: [PATCH 03/71] f-1: fix: fix forgeten args #1 Signed-off-by: GnomeZworc --- scripts/deploy.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 9fcd1dd..3345488 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -24,6 +24,7 @@ check_latest_script () { } main () { + echo "$@" [[ -f ./libs/shflags ]] && . ./libs/shflags || eval "$(curl --silent https://git.g3e.fr/H6N/tools/raw/branch/main/libs/shflags)" DEFINE_boolean 'dryrun' false 'Enable dry-run mode' 'd' @@ -31,6 +32,9 @@ main () { DEFINE_string 'repo_path' 'syonad/two/' 'Path of repository' 'r' DEFINE_string 'branch' 'main/' 'Branch name' 'b' + FLAGS "$@" || exit $? + eval set -- "${FLAGS_ARGV}" + check_latest_script "${FLAGS_git_server}${FLAGS_repo_path}raw/branch/${FLAGS_branch}${SCRIPT_PATH}" "${0}" } From b25ce92c66abbe878ff669f1b05de870a93fba12 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 14:30:04 +0100 Subject: [PATCH 04/71] f-1: scripts: edit script add dry-run Signed-off-by: GnomeZworc --- scripts/deploy.sh | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 3345488..635803f 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -11,6 +11,21 @@ esac SCRIPT_PATH="scripts/deploy.sh" +exec_with_dry_run () { + if [[ ${1} -eq ${FLAGS_TRUE} ]]; then + echo "# ${2}" + else + eval "${2}" 2> /tmp/error || \ + { + echo -e "failed with following error"; + output=$(cat /tmp/error | sed -e "s/^/ error -> /g"); + echo -e "${output}"; + return 1; + } + fi + return 0 +} + check_latest_script () { REMOTE_URL="${1}" LOCAL_PATH="${2}" @@ -18,16 +33,15 @@ check_latest_script () { REMOTE=$(curl --silent "${REMOTE_URL}" | sha256sum) LOCAL=$(cat ${LOCAL_PATH} | sha256sum) - [[ "${REMOTE}" == "${LOCAL}" ]] \ - && echo "both are the same" \ - || echo "not the same" + [[ "${REMOTE}" == "${LOCAL}" ]] || return 1 + return 0 } main () { - echo "$@" [[ -f ./libs/shflags ]] && . ./libs/shflags || eval "$(curl --silent https://git.g3e.fr/H6N/tools/raw/branch/main/libs/shflags)" DEFINE_boolean 'dryrun' false 'Enable dry-run mode' 'd' + DEFINE_boolean 'up_script' true 'Upgrade script' 's' DEFINE_string 'git_server' 'https://git.g3e.fr/' 'Git Server' 'g' DEFINE_string 'repo_path' 'syonad/two/' 'Path of repository' 'r' DEFINE_string 'branch' 'main/' 'Branch name' 'b' @@ -35,7 +49,12 @@ main () { FLAGS "$@" || exit $? eval set -- "${FLAGS_ARGV}" - check_latest_script "${FLAGS_git_server}${FLAGS_repo_path}raw/branch/${FLAGS_branch}${SCRIPT_PATH}" "${0}" + SCRIPT_URL="${FLAGS_git_server}${FLAGS_repo_path}raw/branch/${FLAGS_branch}${SCRIPT_PATH}" + check_latest_script "${SCRIPT_URL}" "${0}" || ( + [[ ${FLAGS_up_script} -eq ${FLAGS_TRUE} ]] && \ + exec_with_dry_run "${FLAGS_dryrun}" "curl --silent \"${SCRIPT_URL}\" -o \"${0}\"" + exit 1 + ) } [[ "${BASH_SOURCE[0]}" == "${0}" ]] && (main "$@" || exit 1) From 6ed9d8abd924cabf6796852f01b995c6edb5ef77 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 15:29:09 +0100 Subject: [PATCH 05/71] f-1: scripts: add download scipts #1 Signed-off-by: GnomeZworc --- scripts/deploy.sh | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 635803f..8feee6f 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -37,6 +37,33 @@ check_latest_script () { return 0 } +download_binaries () { + DRY_RUN="${1}" + TAG="${2}" + GIT_SERVER="${3}" + REPO_PATH="${4}" + + #'.[0].assets.[].browser_download_url' + [[ "${TAG}" == "" ]] && TAG=$(curl --silent "${GIT_SERVER}api/v1/repos/${REPO_PATH}releases/?limit=1" | jq -r '.[0].tag_name') + echo "${TAG}" + + BIN_PATH="/opt/two/${TAG}/bin/" + LN_PATH="/opt/two/bin/" + + exec_with_dry_run "${DRY_RUN}" "mkdir -p \"${BIN_PATH}\"" + exec_with_dry_run "${DRY_RUN}" "mkdir -p \"${LN_PATH}\"" + + curl --silent "${GIT_SERVER}api/v1/repos/${REPO_PATH}releases/tags/${TAG}" | jq -c '.assets.[]' | while read tmp + do + BINARY_NAME=$(echo "${tmp}" | jq -r '.name') + BINARY_SHORT_NAME=$(echo "${BINARY_NAME}" | cut -d_ -f 1) + BINARY_URL=$(echo "${tmp}" | jq -r '.browser_download_url') + exec_with_dry_run "${DRY_RUN}" "curl --silent '${BINARY_URL}' -o '${BIN_PATH}${BINARY_NAME}'" + exec_with_dry_run "${DRY_RUN}" "rm -f '${LN_PATH}${BINARY_SHORT_NAME}'" + exec_with_dry_run "${DRY_RUN}" "ln -s '${BIN_PATH}${BINARY_NAME}' '${LN_PATH}${BINARY_SHORT_NAME}'" + done +} + main () { [[ -f ./libs/shflags ]] && . ./libs/shflags || eval "$(curl --silent https://git.g3e.fr/H6N/tools/raw/branch/main/libs/shflags)" @@ -45,6 +72,7 @@ main () { DEFINE_string 'git_server' 'https://git.g3e.fr/' 'Git Server' 'g' DEFINE_string 'repo_path' 'syonad/two/' 'Path of repository' 'r' DEFINE_string 'branch' 'main/' 'Branch name' 'b' + DEFINE_string 'tag' '' 'Tag name' 't' FLAGS "$@" || exit $? eval set -- "${FLAGS_ARGV}" @@ -52,9 +80,11 @@ main () { SCRIPT_URL="${FLAGS_git_server}${FLAGS_repo_path}raw/branch/${FLAGS_branch}${SCRIPT_PATH}" check_latest_script "${SCRIPT_URL}" "${0}" || ( [[ ${FLAGS_up_script} -eq ${FLAGS_TRUE} ]] && \ - exec_with_dry_run "${FLAGS_dryrun}" "curl --silent \"${SCRIPT_URL}\" -o \"${0}\"" + exec_with_dry_run "${FLAGS_dryrun}" "curl --silent '${SCRIPT_URL}' -o '${0}'" exit 1 ) + + download_binaries "${FLAGS_dryrun}" "${FLAGS_tag}" "${FLAGS_git_server}" "${FLAGS_repo_path}" } [[ "${BASH_SOURCE[0]}" == "${0}" ]] && (main "$@" || exit 1) From ec1d1e0588fb486399e58df9ed5e963bed149c2f Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 23:04:34 +0100 Subject: [PATCH 06/71] f-1: scripts: fix jq parsing for linux Signed-off-by: GnomeZworc --- scripts/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 8feee6f..ddd9795 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -53,7 +53,7 @@ download_binaries () { exec_with_dry_run "${DRY_RUN}" "mkdir -p \"${BIN_PATH}\"" exec_with_dry_run "${DRY_RUN}" "mkdir -p \"${LN_PATH}\"" - curl --silent "${GIT_SERVER}api/v1/repos/${REPO_PATH}releases/tags/${TAG}" | jq -c '.assets.[]' | while read tmp + curl --silent "${GIT_SERVER}api/v1/repos/${REPO_PATH}releases/tags/${TAG}" | jq -c '.assets[]' | while read tmp do BINARY_NAME=$(echo "${tmp}" | jq -r '.name') BINARY_SHORT_NAME=$(echo "${BINARY_NAME}" | cut -d_ -f 1) From 8d4a66bc89fa4db3a9f6797d5a4aa312643828d4 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 23:05:26 +0100 Subject: [PATCH 07/71] f-1: scripts: add change execut for db #1 Signed-off-by: GnomeZworc --- scripts/deploy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index ddd9795..5fb0068 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -59,6 +59,7 @@ download_binaries () { BINARY_SHORT_NAME=$(echo "${BINARY_NAME}" | cut -d_ -f 1) BINARY_URL=$(echo "${tmp}" | jq -r '.browser_download_url') exec_with_dry_run "${DRY_RUN}" "curl --silent '${BINARY_URL}' -o '${BIN_PATH}${BINARY_NAME}'" + exec_with_dry_run "${DRY_RUN}" "chmod +x '${BIN_PATH}${BINARY_NAME}'" exec_with_dry_run "${DRY_RUN}" "rm -f '${LN_PATH}${BINARY_SHORT_NAME}'" exec_with_dry_run "${DRY_RUN}" "ln -s '${BIN_PATH}${BINARY_NAME}' '${LN_PATH}${BINARY_SHORT_NAME}'" done From fc6bb43616c5427c7c6289dd38cf6616139dfaff Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 23:06:02 +0100 Subject: [PATCH 08/71] f-1: scripts: add correct echo Signed-off-by: GnomeZworc --- scripts/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 5fb0068..7532b14 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -45,7 +45,7 @@ download_binaries () { #'.[0].assets.[].browser_download_url' [[ "${TAG}" == "" ]] && TAG=$(curl --silent "${GIT_SERVER}api/v1/repos/${REPO_PATH}releases/?limit=1" | jq -r '.[0].tag_name') - echo "${TAG}" + echo "Deploy ${TAG} binaries" BIN_PATH="/opt/two/${TAG}/bin/" LN_PATH="/opt/two/bin/" From 3831aa2d71cf05143c77ee8902c322b5e8aa1cde Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 23:39:14 +0100 Subject: [PATCH 09/71] f-8: package: add go-systemd #8 Signed-off-by: GnomeZworc --- go.mod | 2 ++ go.sum | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/go.mod b/go.mod index cbc34b5..555ca1b 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.23.8 require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/dgraph-io/badger/v4 v4.8.0 // indirect github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -11,6 +12,7 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect diff --git a/go.sum b/go.sum index 2482f6c..f61e769 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/dgraph-io/badger/v4 v4.8.0 h1:JYph1ChBijCw8SLeybvPINizbDKWZ5n/GYbz2yhN/bs= github.com/dgraph-io/badger/v4 v4.8.0/go.mod h1:U6on6e8k/RTbUWxqKR0MvugJuVmkxSNc79ap4917h4w= github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= @@ -15,6 +17,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= From 6a225a616282149d432dd2a826ba74d157af2814 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 18 Dec 2025 23:39:46 +0100 Subject: [PATCH 10/71] f-8: code: add systemd lib #8 Signed-off-by: GnomeZworc --- pkg/systemd/main.go | 109 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 pkg/systemd/main.go diff --git a/pkg/systemd/main.go b/pkg/systemd/main.go new file mode 100644 index 0000000..ea5fef0 --- /dev/null +++ b/pkg/systemd/main.go @@ -0,0 +1,109 @@ +package systemd + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/coreos/go-systemd/v22/dbus" +) + +const ( + defaultTimeout = 5 * time.Second + jobMode = "replace" +) + +type Manager struct { + conn *dbus.Conn +} + +type ServiceStatus struct { + Name string + LoadState string + ActiveState string + SubState string + MainPID uint32 +} + +// New crée une connexion D-Bus systemd (scope système) +func New() (*Manager, error) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + + conn, err := dbus.NewSystemConnectionContext(ctx) + if err != nil { + return nil, err + } + + return &Manager{conn: conn}, nil +} + +// Close ferme la connexion D-Bus +func (m *Manager) Close() { + if m.conn != nil { + m.conn.Close() + } +} + +// Start démarre un service systemd +func (m *Manager) Start(service string) error { + return m.job("StartUnit", service) +} + +// Stop arrête un service systemd +func (m *Manager) Stop(service string) error { + return m.job("StopUnit", service) +} + +func (m *Manager) job(method, service string) error { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + + ch := make(chan string, 1) + + var err error + switch method { + case "StartUnit": + _, err = m.conn.StartUnitContext(ctx, service, jobMode, ch) + case "StopUnit": + _, err = m.conn.StopUnitContext(ctx, service, jobMode, ch) + default: + return errors.New("unsupported job method") + } + + if err != nil { + return err + } + + result := <-ch + if result != "done" { + return fmt.Errorf("%s %s failed: %s", method, service, result) + } + + return nil +} + +// Status retourne l’état courant du service +func (m *Manager) Status(service string) (*ServiceStatus, error) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + + props, err := m.conn.GetUnitPropertiesContext(ctx, service) + if err != nil { + return nil, err + } + + status := &ServiceStatus{ + Name: service, + LoadState: props["LoadState"].(string), + ActiveState: props["ActiveState"].(string), + SubState: props["SubState"].(string), + } + + if pid, ok := props["MainPID"].(uint32); ok { + status.MainPID = pid + } + + return status, nil +} From 72b2e9afa9bf62d759e7182f206ce561f0b622c4 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 22 Dec 2025 22:49:17 +0100 Subject: [PATCH 11/71] f-8: code: add first agent binari #8 Signed-off-by: GnomeZworc --- cmd/agent/main.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 cmd/agent/main.go diff --git a/cmd/agent/main.go b/cmd/agent/main.go new file mode 100644 index 0000000..bcb3849 --- /dev/null +++ b/cmd/agent/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + bin_name := os.Args[0] + + fmt.Printf("%s: Start process\n", bin_name) + + os.Exit(5) +} From e1f317aeb9be38d5b74bb35f5e923f27d7bb03fc Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Tue, 23 Dec 2025 23:24:14 +0100 Subject: [PATCH 12/71] f-8: code: first implement of metadata cli #8 Signed-off-by: GnomeZworc --- cmd/meta_cli/main.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 cmd/meta_cli/main.go diff --git a/cmd/meta_cli/main.go b/cmd/meta_cli/main.go new file mode 100644 index 0000000..9fec4db --- /dev/null +++ b/cmd/meta_cli/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + "os" +) + +var ( + bin_name = os.Args[0] +) + +func main() { + + fmt.Printf("Start %s conf\n", bin_name) + + os.Exit(0) +} From 1ac5a9fe4996679e32073e23db24a87b45c4289f Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 24 Dec 2025 14:04:30 +0100 Subject: [PATCH 13/71] f-8: conf: move configuration files #8 Signed-off-by: GnomeZworc --- conf/agent/config.dev.yml | 2 ++ {exemple => conf}/agent/config.exemple.yml | 0 2 files changed, 2 insertions(+) create mode 100644 conf/agent/config.dev.yml rename {exemple => conf}/agent/config.exemple.yml (100%) diff --git a/conf/agent/config.dev.yml b/conf/agent/config.dev.yml new file mode 100644 index 0000000..62cb624 --- /dev/null +++ b/conf/agent/config.dev.yml @@ -0,0 +1,2 @@ +database: + path: "./data/" \ No newline at end of file diff --git a/exemple/agent/config.exemple.yml b/conf/agent/config.exemple.yml similarity index 100% rename from exemple/agent/config.exemple.yml rename to conf/agent/config.exemple.yml From 014ae61dbbc78288abe1d31d81e7504b6bd8b413 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 24 Dec 2025 14:05:47 +0100 Subject: [PATCH 14/71] f-8: internal/conf: delete conf file existance check #8 Signed-off-by: GnomeZworc --- internal/config/agent/struct.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/config/agent/struct.go b/internal/config/agent/struct.go index 12a46d3..c9537bf 100644 --- a/internal/config/agent/struct.go +++ b/internal/config/agent/struct.go @@ -17,9 +17,7 @@ func LoadConfig(path string) (*Config, error) { v.SetDefault("database.path", "/var/lib/two/data/") - if err := v.ReadInConfig(); err != nil { - return nil, err - } + v.ReadInConfig() var cfg Config if err := v.Unmarshal(&cfg); err != nil { From 2418e08ee0c9649925bcf347689a3d63ce8680ae Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 24 Dec 2025 22:02:18 +0100 Subject: [PATCH 15/71] f-8: code: add params for meta_cli #8 Signed-off-by: GnomeZworc --- cmd/meta_cli/main.go | 45 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/cmd/meta_cli/main.go b/cmd/meta_cli/main.go index 9fec4db..ce97286 100644 --- a/cmd/meta_cli/main.go +++ b/cmd/meta_cli/main.go @@ -1,17 +1,54 @@ package main import ( + "flag" "fmt" "os" + "strings" + + configuration "git.g3e.fr/syonad/two/internal/config/agent" + "git.g3e.fr/syonad/two/pkg/db/kv" + "github.com/dgraph-io/badger/v4" ) -var ( - bin_name = os.Args[0] -) +var DB *badger.DB + +func AddInDB(dbName string, line string) error { + // ID = partie avant le premier ';' + id := strings.Split(line, ";")[0] + "/bash" + key := []byte(dbName + "/" + id) + + return DB.Update(func(txn *badger.Txn) error { + return txn.Set(key, []byte(line)) + }) +} func main() { + conf_file := flag.String("conf", "/etc/two/agent.yml", "configuration file") + vm_name := flag.String("vm_name", "", "Nom de la vm") + vpc := flag.String("vpc_name", "", "vpc name") + bind_ip := flag.String("ip", "", "bind ip") + bind_port := flag.String("port", "", "bind port") + ssh_key := flag.String("key", "", "Clef ssh") + password := flag.String("pass", "", "password user") + start := flag.Bool("start", false, "start metadata server") + stop := flag.Bool("stop", false, "stop metadata server") - fmt.Printf("Start %s conf\n", bin_name) + flag.Parse() + + conf, err := configuration.LoadConfig(*conf_file) + if err != nil { + fmt.Println(err) + return + } + fmt.Print(conf) + + DB = kv.InitDB(kv.Config{ + Path: conf.Database.Path, + }) + defer DB.Close() + + fmt.Printf("conf metadata for %s\n - this key %s\n - this password %s\n", *vm_name, *ssh_key, *password) os.Exit(0) } From b43e45488e2e8339ef27af0ea34c0c32b1e9e152 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 26 Dec 2025 23:00:13 +0100 Subject: [PATCH 16/71] f-8: code: add func to control db #8 Signed-off-by: GnomeZworc --- pkg/db/kv/addInDB.go | 11 +++++++++++ pkg/db/kv/deleteInDB.go | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 pkg/db/kv/addInDB.go create mode 100644 pkg/db/kv/deleteInDB.go diff --git a/pkg/db/kv/addInDB.go b/pkg/db/kv/addInDB.go new file mode 100644 index 0000000..44ea19c --- /dev/null +++ b/pkg/db/kv/addInDB.go @@ -0,0 +1,11 @@ +package kv + +import ( + "github.com/dgraph-io/badger/v4" +) + +func AddInDB(db *badger.DB, key string, value string) error { + return db.Update(func(txn *badger.Txn) error { + return txn.Set([]byte(key), []byte(value)) + }) +} diff --git a/pkg/db/kv/deleteInDB.go b/pkg/db/kv/deleteInDB.go new file mode 100644 index 0000000..fe8398e --- /dev/null +++ b/pkg/db/kv/deleteInDB.go @@ -0,0 +1,11 @@ +package kv + +import ( + "github.com/dgraph-io/badger/v4" +) + +func DeleteInDB(db *badger.DB, key string) error { + return db.Update(func(txn *badger.Txn) error { + return txn.Delete([]byte(key)) + }) +} From 55ed2c8e53ca0a8ce740abfa0f9c7bd812301bd4 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 26 Dec 2025 23:00:51 +0100 Subject: [PATCH 17/71] f-8: code: add module to load nocloud in db #8 Signed-off-by: GnomeZworc --- internal/load_db/nocloud/render.go | 50 +++++++++++++++++++ internal/load_db/nocloud/struct.go | 10 ++++ .../load_db/nocloud/templates/meta-data.tmpl | 2 + .../nocloud/templates/network-config.tmpl | 4 ++ .../load_db/nocloud/templates/user-data.tmpl | 3 ++ .../nocloud/templates/vendor-data.tmpl | 13 +++++ 6 files changed, 82 insertions(+) create mode 100644 internal/load_db/nocloud/render.go create mode 100644 internal/load_db/nocloud/struct.go create mode 100644 internal/load_db/nocloud/templates/meta-data.tmpl create mode 100644 internal/load_db/nocloud/templates/network-config.tmpl create mode 100644 internal/load_db/nocloud/templates/user-data.tmpl create mode 100644 internal/load_db/nocloud/templates/vendor-data.tmpl diff --git a/internal/load_db/nocloud/render.go b/internal/load_db/nocloud/render.go new file mode 100644 index 0000000..ad7eee1 --- /dev/null +++ b/internal/load_db/nocloud/render.go @@ -0,0 +1,50 @@ +package nocloud + +import ( + "bytes" + "embed" + "text/template" + + "git.g3e.fr/syonad/two/pkg/db/kv" + "github.com/dgraph-io/badger/v4" +) + +//go:embed templates/*.tmpl +var templateFS embed.FS + +func renderConfig(path string, cfg Config) (string, error) { + tpl, err := template.ParseFS(templateFS, path) + if err != nil { + return "", err + } + + var buf bytes.Buffer + if err := tpl.Execute(&buf, cfg); err != nil { + return "", err + } + + return buf.String(), nil +} + +var DB *badger.DB + +func LoadNcCloudInDB(config Config, db *badger.DB) { + meta_data, _ := renderConfig("templates/meta-data.tmpl", config) + user_data, _ := renderConfig("templates/user-data.tmpl", config) + network_config, _ := renderConfig("templates/network-config.tmpl", config) + vendor_data, _ := renderConfig("templates/vendor-data.tmpl", config) + + DB = db + + kv.AddInDB(DB, "metadata/"+config.Name+"/meta-data", meta_data) + kv.AddInDB(DB, "metadata/"+config.Name+"/user-data", user_data) + kv.AddInDB(DB, "metadata/"+config.Name+"/network-config", network_config) + kv.AddInDB(DB, "metadata/"+config.Name+"/vendor-data", vendor_data) + kv.AddInDB(DB, "metadata/"+config.Name+"/vpc", config.VpcName) + kv.AddInDB(DB, "metadata/"+config.Name+"/bind_ip", config.BindIP) + kv.AddInDB(DB, "metadata/"+config.Name+"/bind_port", config.BindPort) +} + +func UnLoadNoCloudInDB(vm_name string, db *badger.DB) { + kv.DeleteInDB(DB, "metadata/"+vm_name) +} diff --git a/internal/load_db/nocloud/struct.go b/internal/load_db/nocloud/struct.go new file mode 100644 index 0000000..4134000 --- /dev/null +++ b/internal/load_db/nocloud/struct.go @@ -0,0 +1,10 @@ +package nocloud + +type Config struct { + VpcName string + BindIP string + BindPort string + Name string + Password string + SSHKEY string +} diff --git a/internal/load_db/nocloud/templates/meta-data.tmpl b/internal/load_db/nocloud/templates/meta-data.tmpl new file mode 100644 index 0000000..ff876bb --- /dev/null +++ b/internal/load_db/nocloud/templates/meta-data.tmpl @@ -0,0 +1,2 @@ +instance-id: {{ .Name }} +local-hostname: {{ .Name }} diff --git a/internal/load_db/nocloud/templates/network-config.tmpl b/internal/load_db/nocloud/templates/network-config.tmpl new file mode 100644 index 0000000..0f8d052 --- /dev/null +++ b/internal/load_db/nocloud/templates/network-config.tmpl @@ -0,0 +1,4 @@ +version: 2 +ethernets: + eth0: + dhcp4: true diff --git a/internal/load_db/nocloud/templates/user-data.tmpl b/internal/load_db/nocloud/templates/user-data.tmpl new file mode 100644 index 0000000..84195ab --- /dev/null +++ b/internal/load_db/nocloud/templates/user-data.tmpl @@ -0,0 +1,3 @@ +#!/bin/sh + +passwd -d root diff --git a/internal/load_db/nocloud/templates/vendor-data.tmpl b/internal/load_db/nocloud/templates/vendor-data.tmpl new file mode 100644 index 0000000..148d6db --- /dev/null +++ b/internal/load_db/nocloud/templates/vendor-data.tmpl @@ -0,0 +1,13 @@ +#cloud-config +users: + - name: syonad + lock_passwd: false + gecos: alpine Cloud User + groups: [adm, wheel] + doas: + - permit nopass syonad + sudo: ["ALL=(ALL) NOPASSWD:ALL"] + shell: /bin/ash + passwd: "{{ .Password }}" + ssh_authorized_keys: + - "{{ .SSHKEY }}" \ No newline at end of file From 1ac1e6186487d4223320bfb420cdbc60741ca58f Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 26 Dec 2025 23:02:14 +0100 Subject: [PATCH 18/71] f-8: code: move binary name #8 Signed-off-by: GnomeZworc --- cmd/agent/main.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/agent/main.go b/cmd/agent/main.go index bcb3849..0f82e93 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -5,10 +5,13 @@ import ( "os" ) +var ( + bin_name = os.Args[0] +) + func main() { - bin_name := os.Args[0] fmt.Printf("%s: Start process\n", bin_name) - os.Exit(5) + os.Exit(0) } From df95d8b4a79fceaa0b790df081afda5b1850e2ec Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 26 Dec 2025 23:40:03 +0100 Subject: [PATCH 19/71] f-8: code: use flags in db binary #8 Signed-off-by: GnomeZworc --- cmd/db/main.go | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/cmd/db/main.go b/cmd/db/main.go index 0c6c1ba..205d8bf 100644 --- a/cmd/db/main.go +++ b/cmd/db/main.go @@ -1,6 +1,7 @@ package main import ( + "flag" "fmt" "os" "strings" @@ -125,7 +126,13 @@ func printDB() { } func main() { - conf, err := configuration.LoadConfig("/etc/two/agent.yml") + conf_file := flag.String("conf", "/etc/two/agent.yml", "configuration file") + + flag.Parse() + + args := flag.Args() + + conf, err := configuration.LoadConfig(*conf_file) if err != nil { fmt.Println(err) return @@ -136,53 +143,53 @@ func main() { }) defer DB.Close() - if len(os.Args) < 2 { + if len(args) < 1 { fmt.Println("Usage: db [args...]") return } - cmd := os.Args[1] + cmd := args[0] switch cmd { case "check_in_db": - if len(os.Args) != 4 { + if len(args) != 3 { fmt.Println("Usage: check_in_db ") os.Exit(1) } - ret := CheckInDB(os.Args[2], os.Args[3]) + ret := CheckInDB(args[1], args[2]) os.Exit(ret) case "add_in_db": - if len(os.Args) < 4 { + if len(args) < 3 { fmt.Println("Usage: add_in_db ") os.Exit(1) } - line := strings.Join(os.Args[3:], ";") - if err := AddInDB(os.Args[2], line); err != nil { + line := strings.Join(args[2:], ";") + if err := AddInDB(args[1], line); err != nil { fmt.Println("Error:", err) os.Exit(1) } case "delete_in_db": - if len(os.Args) != 4 { + if len(args) != 3 { fmt.Println("Usage: delete_in_db ") os.Exit(1) } - if err := DeleteInDB(os.Args[2], os.Args[3]); err != nil { + if err := DeleteInDB(args[1], args[2]); err != nil { fmt.Println("Error:", err) os.Exit(1) } case "count_in_db": - if len(os.Args) != 4 { + if len(args) != 3 { fmt.Println("Usage: count_in_db ") os.Exit(1) } - count := CountInDB(os.Args[2], os.Args[3]) + count := CountInDB(args[1], args[2]) fmt.Println(count) case "get_from_db": - if len(os.Args) != 4 { + if len(args) != 3 { fmt.Println("Usage: get_from_db ") os.Exit(1) } - line, _ := GetFromDB(os.Args[2], os.Args[3]) + line, _ := GetFromDB(args[1], args[2]) fmt.Println(line) case "print": printDB() From b2d1922eaa7b809034e50cbdb5ef9ae8bc9a3af6 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 26 Dec 2025 23:42:24 +0100 Subject: [PATCH 20/71] f-8: pkg: make delete in db recursif #8 Signed-off-by: GnomeZworc --- pkg/db/kv/deleteInDB.go | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/pkg/db/kv/deleteInDB.go b/pkg/db/kv/deleteInDB.go index fe8398e..36d8669 100644 --- a/pkg/db/kv/deleteInDB.go +++ b/pkg/db/kv/deleteInDB.go @@ -1,11 +1,44 @@ package kv import ( + "fmt" + "log" + "github.com/dgraph-io/badger/v4" ) -func DeleteInDB(db *badger.DB, key string) error { +func deleteKey(db *badger.DB, key string) error { return db.Update(func(txn *badger.Txn) error { return txn.Delete([]byte(key)) }) } + +func DeleteInDB(db *badger.DB, key string) error { + + prefix := []byte(key + "/") + + err := db.View(func(txn *badger.Txn) error { + opts := badger.DefaultIteratorOptions + opts.PrefetchValues = false + + it := txn.NewIterator(opts) + defer it.Close() + + for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() { + item := it.Item() + key := item.Key() + + k := append([]byte{}, key...) + fmt.Println(string(k)) + if err := deleteKey(db, string(k)); err != nil { + return err + } + } + return nil + }) + if err != nil { + log.Fatal(err) + } + + return deleteKey(db, key) +} From 38f2ed1b83190cb9b7434659d17968d1d25684c4 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 26 Dec 2025 23:43:29 +0100 Subject: [PATCH 21/71] f-8: code: use recursive delete #8 Signed-off-by: GnomeZworc --- cmd/db/main.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd/db/main.go b/cmd/db/main.go index 205d8bf..765cad0 100644 --- a/cmd/db/main.go +++ b/cmd/db/main.go @@ -60,9 +60,7 @@ func AddInDB(dbName string, line string) error { func DeleteInDB(dbName, id string) error { key := []byte(dbName + "/" + id + "/bash") - return DB.Update(func(txn *badger.Txn) error { - return txn.Delete(key) - }) + return kv.DeleteInDB(DB, string(key)) } func CountInDB(dbName, id string) int { From 97132550b0b000e53cee7801152c1f84d04099f2 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 26 Dec 2025 23:46:18 +0100 Subject: [PATCH 22/71] f-8: code: move Load in DB to internal lib #8 Signed-off-by: GnomeZworc --- cmd/meta_cli/main.go | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/cmd/meta_cli/main.go b/cmd/meta_cli/main.go index ce97286..971c370 100644 --- a/cmd/meta_cli/main.go +++ b/cmd/meta_cli/main.go @@ -3,26 +3,12 @@ package main import ( "flag" "fmt" - "os" - "strings" configuration "git.g3e.fr/syonad/two/internal/config/agent" + "git.g3e.fr/syonad/two/internal/load_db/nocloud" "git.g3e.fr/syonad/two/pkg/db/kv" - "github.com/dgraph-io/badger/v4" ) -var DB *badger.DB - -func AddInDB(dbName string, line string) error { - // ID = partie avant le premier ';' - id := strings.Split(line, ";")[0] + "/bash" - key := []byte(dbName + "/" + id) - - return DB.Update(func(txn *badger.Txn) error { - return txn.Set(key, []byte(line)) - }) -} - func main() { conf_file := flag.String("conf", "/etc/two/agent.yml", "configuration file") vm_name := flag.String("vm_name", "", "Nom de la vm") @@ -43,12 +29,21 @@ func main() { } fmt.Print(conf) - DB = kv.InitDB(kv.Config{ + db := kv.InitDB(kv.Config{ Path: conf.Database.Path, }) - defer DB.Close() + defer db.Close() - fmt.Printf("conf metadata for %s\n - this key %s\n - this password %s\n", *vm_name, *ssh_key, *password) - - os.Exit(0) + if *start { + nocloud.LoadNcCloudInDB(nocloud.Config{ + VpcName: *vpc, + Name: *vm_name, + BindIP: *bind_ip, + BindPort: *bind_port, + Password: *password, + SSHKEY: *ssh_key, + }, db) + } else if *stop { + nocloud.UnLoadNoCloudInDB(*vm_name, db) + } } From c2664e94fa44a822c8e50dc2b5ccf611eb1e2239 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 28 Dec 2025 14:20:12 +0100 Subject: [PATCH 23/71] f-8: clean: use kv func for db bin #8 Signed-off-by: GnomeZworc --- cmd/db/main.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmd/db/main.go b/cmd/db/main.go index 765cad0..8b8d25e 100644 --- a/cmd/db/main.go +++ b/cmd/db/main.go @@ -52,9 +52,7 @@ func AddInDB(dbName string, line string) error { id := strings.Split(line, ";")[0] + "/bash" key := []byte(dbName + "/" + id) - return DB.Update(func(txn *badger.Txn) error { - return txn.Set(key, []byte(line)) - }) + return kv.AddInDB(DB, string(key), line) } func DeleteInDB(dbName, id string) error { From 348eb4aee32b127480087826b5f55ce0c2bb4cbf Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 28 Dec 2025 14:57:36 +0100 Subject: [PATCH 24/71] f-8: code: implemete netns first code #8 Signed-off-by: GnomeZworc --- go.mod | 6 ++++-- go.sum | 2 ++ internal/netns/enter.go | 5 +++++ internal/netns/enter_linux.go | 26 ++++++++++++++++++++++++++ internal/netns/enter_other.go | 8 ++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 internal/netns/enter.go create mode 100644 internal/netns/enter_linux.go create mode 100644 internal/netns/enter_other.go diff --git a/go.mod b/go.mod index 555ca1b..26bd137 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module git.g3e.fr/syonad/two -go 1.23.8 +go 1.24.0 + +toolchain go1.24.11 require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -29,7 +31,7 @@ require ( go.opentelemetry.io/otel/trace v1.37.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/net v0.41.0 // indirect - golang.org/x/sys v0.34.0 // indirect + golang.org/x/sys v0.39.0 // indirect golang.org/x/text v0.28.0 // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/go.sum b/go.sum index f61e769..0d19489 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,8 @@ golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= diff --git a/internal/netns/enter.go b/internal/netns/enter.go new file mode 100644 index 0000000..68ea372 --- /dev/null +++ b/internal/netns/enter.go @@ -0,0 +1,5 @@ +package netns + +func Enter(name string) error { + return enter(name) +} diff --git a/internal/netns/enter_linux.go b/internal/netns/enter_linux.go new file mode 100644 index 0000000..04e116a --- /dev/null +++ b/internal/netns/enter_linux.go @@ -0,0 +1,26 @@ +//go:build linux + +package netns + +import ( + "fmt" + "os" + "runtime" + + "golang.org/x/sys/unix" +) + +func enter(name string) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + path := fmt.Sprintf("/var/run/netns/%s", name) + + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + + return unix.Setns(int(f.Fd()), unix.CLONE_NEWNET) +} diff --git a/internal/netns/enter_other.go b/internal/netns/enter_other.go new file mode 100644 index 0000000..2691ff2 --- /dev/null +++ b/internal/netns/enter_other.go @@ -0,0 +1,8 @@ +//go:build !linux + +package netns + +func enter(name string) error { + // Ignoré hors Linux + return nil +} From 2c6c1ff2dfb1f0c0eaf590e2fff2452db6285c7b Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 28 Dec 2025 14:58:09 +0100 Subject: [PATCH 25/71] f-8: code: use local usage of netns #8 Signed-off-by: GnomeZworc --- internal/metadata/server.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/internal/metadata/server.go b/internal/metadata/server.go index 336f754..2e43a1a 100644 --- a/internal/metadata/server.go +++ b/internal/metadata/server.go @@ -9,14 +9,17 @@ import ( "net" "net/http" "time" + + "git.g3e.fr/syonad/two/internal/netns" ) var data NoCloudData var ( - iface = flag.String("interface", "0.0.0.0", "Interface IP à écouter") - port = flag.Int("port", 8080, "Port à utiliser") - file = flag.String("file", "", "Fichier JSON contenant les données NoCloud") + iface = flag.String("interface", "0.0.0.0", "Interface IP à écouter") + port = flag.Int("port", 8080, "Port à utiliser") + file = flag.String("file", "", "Fichier JSON contenant les données NoCloud") + netns_name = flag.String("netns", "", "Network namespace à utiliser") ) func getIP(r *http.Request) string { @@ -54,6 +57,12 @@ func rootHandler(w http.ResponseWriter, r *http.Request) { func StartServer() { flag.Parse() + if *netns_name != "" { + if err := netns.Enter(*netns_name); err != nil { + log.Fatalf("Impossible d'entrer dans le netns: %v", err) + } + } + if *file == "" { log.Fatal("Vous devez spécifier un fichier via --file") } From e3583e70215ea8c7624d42121c8cef555c046446 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 28 Dec 2025 15:01:37 +0100 Subject: [PATCH 26/71] f-8: import local info for start/deploy metadata #8 Signed-off-by: GnomeZworc --- systemd/metadata_service/metadata@.service | 10 ++++++++++ systemd/metadata_start/run-metadata-in-netns.sh | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 systemd/metadata_service/metadata@.service create mode 100644 systemd/metadata_start/run-metadata-in-netns.sh diff --git a/systemd/metadata_service/metadata@.service b/systemd/metadata_service/metadata@.service new file mode 100644 index 0000000..54cf08a --- /dev/null +++ b/systemd/metadata_service/metadata@.service @@ -0,0 +1,10 @@ +[Unit] +Description=metadata in netns %i +After=network.target + +[Service] +Type=simple +ExecStart=/usr/local/bin/run-metadata-in-netns.sh %i + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/systemd/metadata_start/run-metadata-in-netns.sh b/systemd/metadata_start/run-metadata-in-netns.sh new file mode 100644 index 0000000..612dd18 --- /dev/null +++ b/systemd/metadata_start/run-metadata-in-netns.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +# Expects one argument: netns_bridge (e.g. vpc-00003_br-00002 or vpc1_br0) +arg="$1" +NETNS="${arg%%_*}" +ip_port="${arg#*_}" +IP="${ip_port%%-*}" +PORT="${ip_port#*-}" + +echo "start metadata ${NETNS} " + +exec ip netns exec "${NETNS}" \ + /usr/bin/metadata \ + -file "/opt/metadata/${arg}.conf" \ + -interface "${IP}" \ + -port "${PORT}" \ No newline at end of file From 7b43cecc577330db6628eb9babe352ccb9c91b14 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 29 Dec 2025 23:35:24 +0100 Subject: [PATCH 27/71] f-8: ci: add two binaries #8 Signed-off-by: GnomeZworc --- .forgejo/workflows/prerelease.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index fcb74c6..c6ea322 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -32,7 +32,7 @@ jobs: matrix: goos: [linux] goarch: [amd64] - binaries: [db, metadata] + binaries: [db, metadata, meta_cli, agent] uses: ./.forgejo/workflows/build.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} From fc624e7e961cf283b604937dfc9ca7f8398cc2b2 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Tue, 30 Dec 2025 21:27:35 +0100 Subject: [PATCH 28/71] f-8: code: move flags from pkg to binari #8 Signed-off-by: GnomeZworc --- cmd/metadata/main.go | 23 ++++++++++++++++++++++- internal/metadata/server.go | 24 +++++------------------- internal/metadata/struct.go | 7 +++++++ 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/cmd/metadata/main.go b/cmd/metadata/main.go index 54bae88..dc5bf29 100644 --- a/cmd/metadata/main.go +++ b/cmd/metadata/main.go @@ -1,9 +1,30 @@ package main import ( + "flag" + "log" + "git.g3e.fr/syonad/two/internal/metadata" ) +var ( + iface = flag.String("interface", "0.0.0.0", "Interface IP à écouter") + port = flag.Int("port", 8080, "Port à utiliser") + file = flag.String("file", "", "Fichier JSON contenant les données NoCloud") + netns_name = flag.String("netns", "", "Network namespace à utiliser") +) + func main() { - metadata.StartServer() + flag.Parse() + + if *file == "" { + log.Fatal("Vous devez spécifier un fichier via --file") + } + + metadata.StartServer(metadata.Config{ + Netns: *netns_name, + File: *file, + Iface: *iface, + Port: *port, + }) } diff --git a/internal/metadata/server.go b/internal/metadata/server.go index 2e43a1a..1cb9559 100644 --- a/internal/metadata/server.go +++ b/internal/metadata/server.go @@ -2,7 +2,6 @@ package metadata import ( "encoding/json" - "flag" "fmt" "io/ioutil" "log" @@ -15,13 +14,6 @@ import ( var data NoCloudData -var ( - iface = flag.String("interface", "0.0.0.0", "Interface IP à écouter") - port = flag.Int("port", 8080, "Port à utiliser") - file = flag.String("file", "", "Fichier JSON contenant les données NoCloud") - netns_name = flag.String("netns", "", "Network namespace à utiliser") -) - func getIP(r *http.Request) string { ip, _, err := net.SplitHostPort(r.RemoteAddr) if err != nil { @@ -54,20 +46,14 @@ func rootHandler(w http.ResponseWriter, r *http.Request) { } } -func StartServer() { - flag.Parse() - - if *netns_name != "" { - if err := netns.Enter(*netns_name); err != nil { +func StartServer(config Config) { + if config.Netns != "" { + if err := netns.Enter(config.Netns); err != nil { log.Fatalf("Impossible d'entrer dans le netns: %v", err) } } - if *file == "" { - log.Fatal("Vous devez spécifier un fichier via --file") - } - - raw, err := ioutil.ReadFile(*file) + raw, err := ioutil.ReadFile(config.File) if err != nil { log.Fatalf("Erreur de lecture du fichier: %v", err) } @@ -78,7 +64,7 @@ func StartServer() { http.HandleFunc("/", rootHandler) - address := fmt.Sprintf("%s:%d", *iface, *port) + address := fmt.Sprintf("%s:%d", config.Iface, config.Port) log.Printf("Serveur NoCloud démarré sur http://%s/", address) log.Fatal(http.ListenAndServe(address, nil)) } diff --git a/internal/metadata/struct.go b/internal/metadata/struct.go index f1edf18..bbf4bd7 100644 --- a/internal/metadata/struct.go +++ b/internal/metadata/struct.go @@ -6,3 +6,10 @@ type NoCloudData struct { NetworkConfig string `json:"network-config"` VendorData string `json:"vendor-data"` } + +type Config struct { + Netns string + File string + Iface string + Port int +} From d2bc7e5b7a131ba49fa3d5d4caa354625e1eb770 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Tue, 30 Dec 2025 22:31:19 +0100 Subject: [PATCH 29/71] f-8: code: use db for database config #8 Signed-off-by: GnomeZworc --- cmd/metadata/main.go | 19 +++++------ internal/metadata/server.go | 63 ++++++++++++++++++++++++++++--------- internal/metadata/struct.go | 21 ++++++++----- pkg/db/kv/getInDB.go | 22 +++++++++++++ 4 files changed, 92 insertions(+), 33 deletions(-) create mode 100644 pkg/db/kv/getInDB.go diff --git a/cmd/metadata/main.go b/cmd/metadata/main.go index dc5bf29..4813ed5 100644 --- a/cmd/metadata/main.go +++ b/cmd/metadata/main.go @@ -2,29 +2,26 @@ package main import ( "flag" - "log" "git.g3e.fr/syonad/two/internal/metadata" ) var ( iface = flag.String("interface", "0.0.0.0", "Interface IP à écouter") - port = flag.Int("port", 8080, "Port à utiliser") - file = flag.String("file", "", "Fichier JSON contenant les données NoCloud") + port = flag.Int("port", 0, "Port à utiliser") netns_name = flag.String("netns", "", "Network namespace à utiliser") + conf_file = flag.String("conf", "/etc/two/agent.yml", "configuration file") + vm_name = flag.String("vm", "", "Name of the vm") ) func main() { flag.Parse() - if *file == "" { - log.Fatal("Vous devez spécifier un fichier via --file") - } - metadata.StartServer(metadata.Config{ - Netns: *netns_name, - File: *file, - Iface: *iface, - Port: *port, + Netns: *netns_name, + Iface: *iface, + Port: *port, + ConfFile: *conf_file, + VmName: *vm_name, }) } diff --git a/internal/metadata/server.go b/internal/metadata/server.go index 1cb9559..831aa80 100644 --- a/internal/metadata/server.go +++ b/internal/metadata/server.go @@ -1,15 +1,15 @@ package metadata import ( - "encoding/json" "fmt" - "io/ioutil" "log" "net" "net/http" + "strconv" "time" "git.g3e.fr/syonad/two/internal/netns" + "git.g3e.fr/syonad/two/pkg/db/kv" ) var data NoCloudData @@ -22,6 +22,48 @@ func getIP(r *http.Request) string { return ip } +func getFromDB(config Config) NoCloudData { + var netns_name string + var port int + var iface string + + db := kv.InitDB(kv.Config{Path: config.ConfFile}) + + metadata, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/meta-data") + userdata, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/user-data") + networkconfig, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/network-config") + vendordata, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/vendor-data") + + if config.Netns == "" { + netns_name, _ = kv.GetFromDB(db, "metadata/"+config.VmName+"/vpc") + } else { + netns_name = config.Netns + } + + if config.Iface == "" { + iface, _ = kv.GetFromDB(db, "metadata/"+config.VmName+"/bind_ip") + } else { + iface = config.Iface + } + + if config.Port == 0 { + sport, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/bind_port") + port, _ = strconv.Atoi(sport) + } else { + port = config.Port + } + + return NoCloudData{ + MetaData: metadata, + UserData: userdata, + NetworkConfig: networkconfig, + VendorData: vendordata, + NetNs: netns_name, + Iface: iface, + Port: port, + } +} + func rootHandler(w http.ResponseWriter, r *http.Request) { ip := getIP(r) path := r.URL.Path @@ -47,24 +89,17 @@ func rootHandler(w http.ResponseWriter, r *http.Request) { } func StartServer(config Config) { - if config.Netns != "" { - if err := netns.Enter(config.Netns); err != nil { + data = getFromDB(config) + + if data.NetNs != "" { + if err := netns.Enter(data.NetNs); err != nil { log.Fatalf("Impossible d'entrer dans le netns: %v", err) } } - raw, err := ioutil.ReadFile(config.File) - if err != nil { - log.Fatalf("Erreur de lecture du fichier: %v", err) - } - - if err := json.Unmarshal(raw, &data); err != nil { - log.Fatalf("Erreur de parsing JSON: %v", err) - } - http.HandleFunc("/", rootHandler) - address := fmt.Sprintf("%s:%d", config.Iface, config.Port) + address := fmt.Sprintf("%s:%d", data.Iface, data.Port) log.Printf("Serveur NoCloud démarré sur http://%s/", address) log.Fatal(http.ListenAndServe(address, nil)) } diff --git a/internal/metadata/struct.go b/internal/metadata/struct.go index bbf4bd7..9e95341 100644 --- a/internal/metadata/struct.go +++ b/internal/metadata/struct.go @@ -1,15 +1,20 @@ package metadata type NoCloudData struct { - MetaData string `json:"meta-data"` - UserData string `json:"user-data"` - NetworkConfig string `json:"network-config"` - VendorData string `json:"vendor-data"` + MetaData string + UserData string + NetworkConfig string + VendorData string + NetNs string + Iface string + Port int } type Config struct { - Netns string - File string - Iface string - Port int + Netns string + File string + Iface string + Port int + ConfFile string + VmName string } diff --git a/pkg/db/kv/getInDB.go b/pkg/db/kv/getInDB.go new file mode 100644 index 0000000..bfe7590 --- /dev/null +++ b/pkg/db/kv/getInDB.go @@ -0,0 +1,22 @@ +package kv + +import ( + "github.com/dgraph-io/badger/v4" +) + +func GetFromDB(db *badger.DB, key string) (string, error) { + var result string + + err := db.View(func(txn *badger.Txn) error { + item, err := txn.Get([]byte(key)) + if err != nil { + return err + } + return item.Value(func(val []byte) error { + result = string(val) + return nil + }) + }) + + return result, err +} From f3898b288dfba0b70861097dfcc5ae5b20a4c5ea Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 1 Jan 2026 23:19:25 +0100 Subject: [PATCH 30/71] f-8: code: set correct config path and data path #8 Signed-off-by: GnomeZworc --- internal/metadata/server.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/metadata/server.go b/internal/metadata/server.go index 831aa80..e44edaf 100644 --- a/internal/metadata/server.go +++ b/internal/metadata/server.go @@ -8,6 +8,7 @@ import ( "strconv" "time" + configuration "git.g3e.fr/syonad/two/internal/config/agent" "git.g3e.fr/syonad/two/internal/netns" "git.g3e.fr/syonad/two/pkg/db/kv" ) @@ -27,7 +28,9 @@ func getFromDB(config Config) NoCloudData { var port int var iface string - db := kv.InitDB(kv.Config{Path: config.ConfFile}) + conf_db, _ := configuration.LoadConfig(config.ConfFile) + + db := kv.InitDB(kv.Config{Path: conf_db.Database.Path}) metadata, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/meta-data") userdata, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/user-data") From 7dbb508058f34037e50f314ef5739ccfd0f1a9e2 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 1 Jan 2026 23:24:11 +0100 Subject: [PATCH 31/71] f-8: fix: close db for metadata Signed-off-by: GnomeZworc --- internal/metadata/server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/metadata/server.go b/internal/metadata/server.go index e44edaf..a72a52e 100644 --- a/internal/metadata/server.go +++ b/internal/metadata/server.go @@ -31,6 +31,7 @@ func getFromDB(config Config) NoCloudData { conf_db, _ := configuration.LoadConfig(config.ConfFile) db := kv.InitDB(kv.Config{Path: conf_db.Database.Path}) + defer db.Close() metadata, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/meta-data") userdata, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/user-data") From 87879048338f86db1bf9035abeb1d279fec133dc Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 2 Jan 2026 22:51:15 +0100 Subject: [PATCH 32/71] f-8: code: add readonly feature in kv db #8 Signed-off-by: GnomeZworc --- pkg/db/kv/init.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/db/kv/init.go b/pkg/db/kv/init.go index 18148df..cc09cb0 100644 --- a/pkg/db/kv/init.go +++ b/pkg/db/kv/init.go @@ -4,8 +4,9 @@ import ( "github.com/dgraph-io/badger/v4" ) -func InitDB(conf Config) *badger.DB { - opts := badger.DefaultOptions(conf.Path) +func InitDB(conf Config, readonly bool) *badger.DB { + opts := badger.DefaultOptions(conf.Path). + WithReadOnly(readonly) opts.Logger = nil opts.ValueLogFileSize = 10 << 20 // 10 Mo par fichier vlog opts.NumMemtables = 1 From de7a678640394042ae0dfea4499cac777720ad79 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 2 Jan 2026 22:51:53 +0100 Subject: [PATCH 33/71] f-8: fix: implemente readonly usage #8 Signed-off-by: GnomeZworc --- cmd/db/main.go | 2 +- cmd/meta_cli/main.go | 2 +- internal/metadata/server.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/db/main.go b/cmd/db/main.go index 8b8d25e..1166f44 100644 --- a/cmd/db/main.go +++ b/cmd/db/main.go @@ -136,7 +136,7 @@ func main() { DB = kv.InitDB(kv.Config{ Path: conf.Database.Path, - }) + }, false) defer DB.Close() if len(args) < 1 { diff --git a/cmd/meta_cli/main.go b/cmd/meta_cli/main.go index 971c370..a357991 100644 --- a/cmd/meta_cli/main.go +++ b/cmd/meta_cli/main.go @@ -31,7 +31,7 @@ func main() { db := kv.InitDB(kv.Config{ Path: conf.Database.Path, - }) + }, false) defer db.Close() if *start { diff --git a/internal/metadata/server.go b/internal/metadata/server.go index a72a52e..3a63cdb 100644 --- a/internal/metadata/server.go +++ b/internal/metadata/server.go @@ -30,7 +30,7 @@ func getFromDB(config Config) NoCloudData { conf_db, _ := configuration.LoadConfig(config.ConfFile) - db := kv.InitDB(kv.Config{Path: conf_db.Database.Path}) + db := kv.InitDB(kv.Config{Path: conf_db.Database.Path}, true) defer db.Close() metadata, _ := kv.GetFromDB(db, "metadata/"+config.VmName+"/meta-data") From 93a2bc6d330c42d7abef3fdb130f88ac57bf4505 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 4 Jan 2026 17:42:26 +0100 Subject: [PATCH 34/71] f-8: systemd: change systemd file #8 Signed-off-by: GnomeZworc --- .../{metadata_service => }/metadata@.service | 2 +- systemd/metadata_start/run-metadata-in-netns.sh | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) rename systemd/{metadata_service => }/metadata@.service (69%) delete mode 100644 systemd/metadata_start/run-metadata-in-netns.sh diff --git a/systemd/metadata_service/metadata@.service b/systemd/metadata@.service similarity index 69% rename from systemd/metadata_service/metadata@.service rename to systemd/metadata@.service index 54cf08a..626b97c 100644 --- a/systemd/metadata_service/metadata@.service +++ b/systemd/metadata@.service @@ -4,7 +4,7 @@ After=network.target [Service] Type=simple -ExecStart=/usr/local/bin/run-metadata-in-netns.sh %i +ExecStart=/opt/two/bin/metadata --vm %i [Install] WantedBy=multi-user.target \ No newline at end of file diff --git a/systemd/metadata_start/run-metadata-in-netns.sh b/systemd/metadata_start/run-metadata-in-netns.sh deleted file mode 100644 index 612dd18..0000000 --- a/systemd/metadata_start/run-metadata-in-netns.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -set -e - -# Expects one argument: netns_bridge (e.g. vpc-00003_br-00002 or vpc1_br0) -arg="$1" -NETNS="${arg%%_*}" -ip_port="${arg#*_}" -IP="${ip_port%%-*}" -PORT="${ip_port#*-}" - -echo "start metadata ${NETNS} " - -exec ip netns exec "${NETNS}" \ - /usr/bin/metadata \ - -file "/opt/metadata/${arg}.conf" \ - -interface "${IP}" \ - -port "${PORT}" \ No newline at end of file From 989264681426a5fd472a5c39f8d740c9ddaeae94 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 4 Jan 2026 17:43:51 +0100 Subject: [PATCH 35/71] f-8: code: start/stop metadata service Signed-off-by: GnomeZworc --- cmd/meta_cli/main.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/meta_cli/main.go b/cmd/meta_cli/main.go index a357991..9782b5f 100644 --- a/cmd/meta_cli/main.go +++ b/cmd/meta_cli/main.go @@ -7,6 +7,7 @@ import ( configuration "git.g3e.fr/syonad/two/internal/config/agent" "git.g3e.fr/syonad/two/internal/load_db/nocloud" "git.g3e.fr/syonad/two/pkg/db/kv" + "git.g3e.fr/syonad/two/pkg/systemd" ) func main() { @@ -22,6 +23,8 @@ func main() { flag.Parse() + service, _ := systemd.New() + conf, err := configuration.LoadConfig(*conf_file) if err != nil { fmt.Println(err) @@ -43,7 +46,9 @@ func main() { Password: *password, SSHKEY: *ssh_key, }, db) + service.Start("metadata@" + *vm_name) } else if *stop { nocloud.UnLoadNoCloudInDB(*vm_name, db) + service.Stop("metadata@" + *vm_name) } } From 44b58b36142356811cb094aa2bac44c4e8bfb71c Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 7 Jan 2026 21:06:03 +0100 Subject: [PATCH 36/71] f-11: fix: clean print not usefull #11 Signed-off-by: GnomeZworc --- cmd/meta_cli/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/meta_cli/main.go b/cmd/meta_cli/main.go index 9782b5f..2c7982d 100644 --- a/cmd/meta_cli/main.go +++ b/cmd/meta_cli/main.go @@ -30,7 +30,6 @@ func main() { fmt.Println(err) return } - fmt.Print(conf) db := kv.InitDB(kv.Config{ Path: conf.Database.Path, From 24e3de808891e8a65ce959d2191d220fa6fbfe16 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 7 Jan 2026 21:06:47 +0100 Subject: [PATCH 37/71] f-11: improvement: add a dryrun function Signed-off-by: GnomeZworc --- cmd/meta_cli/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmd/meta_cli/main.go b/cmd/meta_cli/main.go index 2c7982d..18cf391 100644 --- a/cmd/meta_cli/main.go +++ b/cmd/meta_cli/main.go @@ -20,6 +20,7 @@ func main() { password := flag.String("pass", "", "password user") start := flag.Bool("start", false, "start metadata server") stop := flag.Bool("stop", false, "stop metadata server") + dryrun := flag.Bool("dryrun", false, "launch in dry node") flag.Parse() @@ -45,9 +46,13 @@ func main() { Password: *password, SSHKEY: *ssh_key, }, db) - service.Start("metadata@" + *vm_name) + if !*dryrun { + service.Start("metadata@" + *vm_name) + } } else if *stop { nocloud.UnLoadNoCloudInDB(*vm_name, db) - service.Stop("metadata@" + *vm_name) + if !*dryrun { + service.Stop("metadata@" + *vm_name) + } } } From 37e345609e58307487af4e616aa14ca1834680fd Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 7 Jan 2026 21:09:04 +0100 Subject: [PATCH 38/71] f-11: fix: clean error in nocloud work #11 Signed-off-by: GnomeZworc --- internal/load_db/nocloud/render.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/internal/load_db/nocloud/render.go b/internal/load_db/nocloud/render.go index ad7eee1..4fa9386 100644 --- a/internal/load_db/nocloud/render.go +++ b/internal/load_db/nocloud/render.go @@ -26,25 +26,21 @@ func renderConfig(path string, cfg Config) (string, error) { return buf.String(), nil } -var DB *badger.DB - func LoadNcCloudInDB(config Config, db *badger.DB) { meta_data, _ := renderConfig("templates/meta-data.tmpl", config) user_data, _ := renderConfig("templates/user-data.tmpl", config) network_config, _ := renderConfig("templates/network-config.tmpl", config) vendor_data, _ := renderConfig("templates/vendor-data.tmpl", config) - DB = db - - kv.AddInDB(DB, "metadata/"+config.Name+"/meta-data", meta_data) - kv.AddInDB(DB, "metadata/"+config.Name+"/user-data", user_data) - kv.AddInDB(DB, "metadata/"+config.Name+"/network-config", network_config) - kv.AddInDB(DB, "metadata/"+config.Name+"/vendor-data", vendor_data) - kv.AddInDB(DB, "metadata/"+config.Name+"/vpc", config.VpcName) - kv.AddInDB(DB, "metadata/"+config.Name+"/bind_ip", config.BindIP) - kv.AddInDB(DB, "metadata/"+config.Name+"/bind_port", config.BindPort) + kv.AddInDB(db, "metadata/"+config.Name+"/meta-data", meta_data) + kv.AddInDB(db, "metadata/"+config.Name+"/user-data", user_data) + kv.AddInDB(db, "metadata/"+config.Name+"/network-config", network_config) + kv.AddInDB(db, "metadata/"+config.Name+"/vendor-data", vendor_data) + kv.AddInDB(db, "metadata/"+config.Name+"/vpc", config.VpcName) + kv.AddInDB(db, "metadata/"+config.Name+"/bind_ip", config.BindIP) + kv.AddInDB(db, "metadata/"+config.Name+"/bind_port", config.BindPort) } func UnLoadNoCloudInDB(vm_name string, db *badger.DB) { - kv.DeleteInDB(DB, "metadata/"+vm_name) + kv.DeleteInDB(db, "metadata/"+vm_name) } From 9780947805438fc884327528d94f11817ca04ee3 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 7 Jan 2026 21:10:37 +0100 Subject: [PATCH 39/71] f-11: code: change struct name Signed-off-by: GnomeZworc --- cmd/metadata/main.go | 2 +- internal/metadata/server.go | 4 ++-- internal/metadata/struct.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/metadata/main.go b/cmd/metadata/main.go index 4813ed5..96e3f75 100644 --- a/cmd/metadata/main.go +++ b/cmd/metadata/main.go @@ -17,7 +17,7 @@ var ( func main() { flag.Parse() - metadata.StartServer(metadata.Config{ + metadata.StartServer(metadata.ServerConfig{ Netns: *netns_name, Iface: *iface, Port: *port, diff --git a/internal/metadata/server.go b/internal/metadata/server.go index 3a63cdb..3b4e12f 100644 --- a/internal/metadata/server.go +++ b/internal/metadata/server.go @@ -23,7 +23,7 @@ func getIP(r *http.Request) string { return ip } -func getFromDB(config Config) NoCloudData { +func getFromDB(config ServerConfig) NoCloudData { var netns_name string var port int var iface string @@ -92,7 +92,7 @@ func rootHandler(w http.ResponseWriter, r *http.Request) { } } -func StartServer(config Config) { +func StartServer(config ServerConfig) { data = getFromDB(config) if data.NetNs != "" { diff --git a/internal/metadata/struct.go b/internal/metadata/struct.go index 9e95341..f2c364e 100644 --- a/internal/metadata/struct.go +++ b/internal/metadata/struct.go @@ -10,7 +10,7 @@ type NoCloudData struct { Port int } -type Config struct { +type ServerConfig struct { Netns string File string Iface string From a8ffeebb7262f0c8804cc82eeb8e0e6703e85c03 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 7 Jan 2026 23:16:58 +0100 Subject: [PATCH 40/71] f-11: code: move start and stop metadata #11 Signed-off-by: GnomeZworc --- cmd/meta_cli/main.go | 17 +++--------- internal/load_db/nocloud/struct.go | 10 ------- internal/metadata/handle.go | 26 +++++++++++++++++++ .../{load_db/nocloud => metadata}/render.go | 14 +++++----- internal/metadata/struct.go | 9 +++++++ .../templates/meta-data.tmpl | 0 .../templates/network-config.tmpl | 0 .../templates/user-data.tmpl | 0 .../templates/vendor-data.tmpl | 0 9 files changed, 46 insertions(+), 30 deletions(-) delete mode 100644 internal/load_db/nocloud/struct.go create mode 100644 internal/metadata/handle.go rename internal/{load_db/nocloud => metadata}/render.go (70%) rename internal/{load_db/nocloud => metadata}/templates/meta-data.tmpl (100%) rename internal/{load_db/nocloud => metadata}/templates/network-config.tmpl (100%) rename internal/{load_db/nocloud => metadata}/templates/user-data.tmpl (100%) rename internal/{load_db/nocloud => metadata}/templates/vendor-data.tmpl (100%) diff --git a/cmd/meta_cli/main.go b/cmd/meta_cli/main.go index 18cf391..20706d2 100644 --- a/cmd/meta_cli/main.go +++ b/cmd/meta_cli/main.go @@ -5,9 +5,8 @@ import ( "fmt" configuration "git.g3e.fr/syonad/two/internal/config/agent" - "git.g3e.fr/syonad/two/internal/load_db/nocloud" + "git.g3e.fr/syonad/two/internal/metadata" "git.g3e.fr/syonad/two/pkg/db/kv" - "git.g3e.fr/syonad/two/pkg/systemd" ) func main() { @@ -24,8 +23,6 @@ func main() { flag.Parse() - service, _ := systemd.New() - conf, err := configuration.LoadConfig(*conf_file) if err != nil { fmt.Println(err) @@ -38,21 +35,15 @@ func main() { defer db.Close() if *start { - nocloud.LoadNcCloudInDB(nocloud.Config{ + metadata.StartMetadata(metadata.NoCloudConfig{ VpcName: *vpc, Name: *vm_name, BindIP: *bind_ip, BindPort: *bind_port, Password: *password, SSHKEY: *ssh_key, - }, db) - if !*dryrun { - service.Start("metadata@" + *vm_name) - } + }, db, *dryrun) } else if *stop { - nocloud.UnLoadNoCloudInDB(*vm_name, db) - if !*dryrun { - service.Stop("metadata@" + *vm_name) - } + metadata.StopMetadata(*vm_name, db, *dryrun) } } diff --git a/internal/load_db/nocloud/struct.go b/internal/load_db/nocloud/struct.go deleted file mode 100644 index 4134000..0000000 --- a/internal/load_db/nocloud/struct.go +++ /dev/null @@ -1,10 +0,0 @@ -package nocloud - -type Config struct { - VpcName string - BindIP string - BindPort string - Name string - Password string - SSHKEY string -} diff --git a/internal/metadata/handle.go b/internal/metadata/handle.go new file mode 100644 index 0000000..33ac088 --- /dev/null +++ b/internal/metadata/handle.go @@ -0,0 +1,26 @@ +package metadata + +import ( + "git.g3e.fr/syonad/two/pkg/systemd" + "github.com/dgraph-io/badger/v4" +) + +func StartMetadata(config NoCloudConfig, db *badger.DB, dryrun bool) { + service, _ := systemd.New() + defer service.Close() + + LoadNcCloudInDB(config, db) + if !dryrun { + service.Start("metadata@" + config.Name) + } +} + +func StopMetadata(vm_name string, db *badger.DB, dryrun bool) { + service, _ := systemd.New() + defer service.Close() + + UnLoadNoCloudInDB(vm_name, db) + if !dryrun { + service.Stop("metadata@" + vm_name) + } +} diff --git a/internal/load_db/nocloud/render.go b/internal/metadata/render.go similarity index 70% rename from internal/load_db/nocloud/render.go rename to internal/metadata/render.go index 4fa9386..f6c3cae 100644 --- a/internal/load_db/nocloud/render.go +++ b/internal/metadata/render.go @@ -1,4 +1,4 @@ -package nocloud +package metadata import ( "bytes" @@ -12,7 +12,7 @@ import ( //go:embed templates/*.tmpl var templateFS embed.FS -func renderConfig(path string, cfg Config) (string, error) { +func RenderConfig(path string, cfg NoCloudConfig) (string, error) { tpl, err := template.ParseFS(templateFS, path) if err != nil { return "", err @@ -26,11 +26,11 @@ func renderConfig(path string, cfg Config) (string, error) { return buf.String(), nil } -func LoadNcCloudInDB(config Config, db *badger.DB) { - meta_data, _ := renderConfig("templates/meta-data.tmpl", config) - user_data, _ := renderConfig("templates/user-data.tmpl", config) - network_config, _ := renderConfig("templates/network-config.tmpl", config) - vendor_data, _ := renderConfig("templates/vendor-data.tmpl", config) +func LoadNcCloudInDB(config NoCloudConfig, db *badger.DB) { + meta_data, _ := RenderConfig("templates/meta-data.tmpl", config) + user_data, _ := RenderConfig("templates/user-data.tmpl", config) + network_config, _ := RenderConfig("templates/network-config.tmpl", config) + vendor_data, _ := RenderConfig("templates/vendor-data.tmpl", config) kv.AddInDB(db, "metadata/"+config.Name+"/meta-data", meta_data) kv.AddInDB(db, "metadata/"+config.Name+"/user-data", user_data) diff --git a/internal/metadata/struct.go b/internal/metadata/struct.go index f2c364e..5810ff4 100644 --- a/internal/metadata/struct.go +++ b/internal/metadata/struct.go @@ -18,3 +18,12 @@ type ServerConfig struct { ConfFile string VmName string } + +type NoCloudConfig struct { + VpcName string + BindIP string + BindPort string + Name string + Password string + SSHKEY string +} diff --git a/internal/load_db/nocloud/templates/meta-data.tmpl b/internal/metadata/templates/meta-data.tmpl similarity index 100% rename from internal/load_db/nocloud/templates/meta-data.tmpl rename to internal/metadata/templates/meta-data.tmpl diff --git a/internal/load_db/nocloud/templates/network-config.tmpl b/internal/metadata/templates/network-config.tmpl similarity index 100% rename from internal/load_db/nocloud/templates/network-config.tmpl rename to internal/metadata/templates/network-config.tmpl diff --git a/internal/load_db/nocloud/templates/user-data.tmpl b/internal/metadata/templates/user-data.tmpl similarity index 100% rename from internal/load_db/nocloud/templates/user-data.tmpl rename to internal/metadata/templates/user-data.tmpl diff --git a/internal/load_db/nocloud/templates/vendor-data.tmpl b/internal/metadata/templates/vendor-data.tmpl similarity index 100% rename from internal/load_db/nocloud/templates/vendor-data.tmpl rename to internal/metadata/templates/vendor-data.tmpl From 07cf77ba7d04902c506e64201a2d0eb954b2c946 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 7 Jan 2026 23:24:43 +0100 Subject: [PATCH 41/71] f-11: fix: rename meta_cli to metacli Signed-off-by: GnomeZworc --- .forgejo/workflows/prerelease.yml | 2 +- cmd/{meta_cli => metacli}/main.go | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename cmd/{meta_cli => metacli}/main.go (100%) diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index c6ea322..0326071 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -32,7 +32,7 @@ jobs: matrix: goos: [linux] goarch: [amd64] - binaries: [db, metadata, meta_cli, agent] + binaries: [db, metadata, metacli, agent] uses: ./.forgejo/workflows/build.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} diff --git a/cmd/meta_cli/main.go b/cmd/metacli/main.go similarity index 100% rename from cmd/meta_cli/main.go rename to cmd/metacli/main.go From 00852ec1d3f6386f310180f3a9e256489b5525e1 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Wed, 7 Jan 2026 23:30:01 +0100 Subject: [PATCH 42/71] f-11: debug: remove debug print from db kv interface #11 Signed-off-by: GnomeZworc --- pkg/db/kv/deleteInDB.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/db/kv/deleteInDB.go b/pkg/db/kv/deleteInDB.go index 36d8669..1943c81 100644 --- a/pkg/db/kv/deleteInDB.go +++ b/pkg/db/kv/deleteInDB.go @@ -1,7 +1,6 @@ package kv import ( - "fmt" "log" "github.com/dgraph-io/badger/v4" @@ -29,7 +28,6 @@ func DeleteInDB(db *badger.DB, key string) error { key := item.Key() k := append([]byte{}, key...) - fmt.Println(string(k)) if err := deleteKey(db, string(k)); err != nil { return err } From 454005d6ac65ea798d7ad72e62ce27dfff485698 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 8 Jan 2026 23:37:35 +0100 Subject: [PATCH 43/71] f-10: code: add create and delete netns #10 Signed-off-by: GnomeZworc --- internal/netns/create.go | 5 ++++ internal/netns/create_linux.go | 55 ++++++++++++++++++++++++++++++++++ internal/netns/create_other.go | 5 ++++ internal/netns/delete.go | 5 ++++ internal/netns/delete_linux.go | 18 +++++++++++ internal/netns/delete_other.go | 5 ++++ internal/netns/exist.go | 14 +++++++++ 7 files changed, 107 insertions(+) create mode 100644 internal/netns/create.go create mode 100644 internal/netns/create_linux.go create mode 100644 internal/netns/create_other.go create mode 100644 internal/netns/delete.go create mode 100644 internal/netns/delete_linux.go create mode 100644 internal/netns/delete_other.go create mode 100644 internal/netns/exist.go diff --git a/internal/netns/create.go b/internal/netns/create.go new file mode 100644 index 0000000..d6ca305 --- /dev/null +++ b/internal/netns/create.go @@ -0,0 +1,5 @@ +package netns + +func Create(name string) error { + return create(name) +} diff --git a/internal/netns/create_linux.go b/internal/netns/create_linux.go new file mode 100644 index 0000000..8ee0afa --- /dev/null +++ b/internal/netns/create_linux.go @@ -0,0 +1,55 @@ +//go:build linux + +package netns + +import ( + "os" + + "golang.org/x/sys/unix" +) + +func create(name string) error { + base := "/var/run/netns" + path := base + "/" + name + + if err := os.MkdirAll(base, 0755); err != nil { + return err + } + + // fichier cible + f, err := os.Create(path) + if err != nil { + return err + } + f.Close() + + // sauvegarde du netns courant + orig, err := os.Open("/proc/self/ns/net") + if err != nil { + return err + } + defer orig.Close() + + // nouveau netns + if err := unix.Unshare(unix.CLONE_NEWNET); err != nil { + return err + } + + // bind mount du netns courant vers /var/run/netns/ + if err := unix.Mount( + "/proc/self/ns/net", + path, + "", + unix.MS_BIND, + "", + ); err != nil { + return err + } + + // revenir au netns original + if err := unix.Setns(int(orig.Fd()), unix.CLONE_NEWNET); err != nil { + return err + } + + return nil +} diff --git a/internal/netns/create_other.go b/internal/netns/create_other.go new file mode 100644 index 0000000..3c0fd66 --- /dev/null +++ b/internal/netns/create_other.go @@ -0,0 +1,5 @@ +//go:build !linux + +package netns + +func create(string) error { return nil } diff --git a/internal/netns/delete.go b/internal/netns/delete.go new file mode 100644 index 0000000..af0a585 --- /dev/null +++ b/internal/netns/delete.go @@ -0,0 +1,5 @@ +package netns + +func Delete(name string) error { + return delete(name) +} diff --git a/internal/netns/delete_linux.go b/internal/netns/delete_linux.go new file mode 100644 index 0000000..ac0af1f --- /dev/null +++ b/internal/netns/delete_linux.go @@ -0,0 +1,18 @@ +//go:build linux + +package netns + +import ( + "os" + + "golang.org/x/sys/unix" +) + +func delete(name string) error { + path := "/var/run/netns/" + name + + if err := unix.Unmount(path, unix.MNT_DETACH); err != nil { + return err + } + return os.Remove(path) +} diff --git a/internal/netns/delete_other.go b/internal/netns/delete_other.go new file mode 100644 index 0000000..186d355 --- /dev/null +++ b/internal/netns/delete_other.go @@ -0,0 +1,5 @@ +//go:build !linux + +package netns + +func delete(string) error { return nil } diff --git a/internal/netns/exist.go b/internal/netns/exist.go new file mode 100644 index 0000000..7783dd9 --- /dev/null +++ b/internal/netns/exist.go @@ -0,0 +1,14 @@ +package netns + +import ( + "os" +) + +func exist(name string) bool { + _, err := os.Stat("/var/run/netns/" + name) + return err == nil +} + +func Exist(name string) bool { + return exist(name) +} From a650a34fc3a424075c48ec9d88b4d77bf1735fe4 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 8 Jan 2026 23:47:52 +0100 Subject: [PATCH 44/71] f-10: code: add function to call a function in a netns #10 Signed-off-by: GnomeZworc --- internal/netns/call.go | 5 ++++ internal/netns/call_linux.go | 44 ++++++++++++++++++++++++++++++++++++ internal/netns/call_other.go | 7 ++++++ 3 files changed, 56 insertions(+) create mode 100644 internal/netns/call.go create mode 100644 internal/netns/call_linux.go create mode 100644 internal/netns/call_other.go diff --git a/internal/netns/call.go b/internal/netns/call.go new file mode 100644 index 0000000..da326fd --- /dev/null +++ b/internal/netns/call.go @@ -0,0 +1,5 @@ +package netns + +func Call(name string, fn func() error) error { + return call(name, fn) +} diff --git a/internal/netns/call_linux.go b/internal/netns/call_linux.go new file mode 100644 index 0000000..b23ac19 --- /dev/null +++ b/internal/netns/call_linux.go @@ -0,0 +1,44 @@ +//go:build linux + +package netns + +import ( + "fmt" + "os" + "runtime" + + "golang.org/x/sys/unix" +) + +func call(name string, fn func() error) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + // sauvegarde du netns courant + orig, err := os.Open("/proc/self/ns/net") + if err != nil { + return err + } + defer orig.Close() + + // entrer dans le netns cible + f, err := os.Open(fmt.Sprintf("/var/run/netns/%s", name)) + if err != nil { + return err + } + defer f.Close() + + if err := unix.Setns(int(f.Fd()), unix.CLONE_NEWNET); err != nil { + return err + } + + // exécuter la fonction dans le netns + err = fn() + + // toujours revenir au netns d'origine + if restoreErr := unix.Setns(int(orig.Fd()), unix.CLONE_NEWNET); restoreErr != nil { + return restoreErr + } + + return err +} diff --git a/internal/netns/call_other.go b/internal/netns/call_other.go new file mode 100644 index 0000000..14a8924 --- /dev/null +++ b/internal/netns/call_other.go @@ -0,0 +1,7 @@ +//go:build !linux + +package netns + +func call(name string, fn func() error) error { + return fn() +} From 0d3d59a019bcc81aa5532f076339214c40cf01c9 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 8 Jan 2026 23:57:35 +0100 Subject: [PATCH 45/71] f-10: bin: add a new binarie #10 Signed-off-by: GnomeZworc --- .forgejo/workflows/prerelease.yml | 2 +- cmd/netns/main.go | 40 +++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 cmd/netns/main.go diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index 0326071..0248db4 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -32,7 +32,7 @@ jobs: matrix: goos: [linux] goarch: [amd64] - binaries: [db, metadata, metacli, agent] + binaries: [db, metadata, metacli, agent, netns] uses: ./.forgejo/workflows/build.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} diff --git a/cmd/netns/main.go b/cmd/netns/main.go new file mode 100644 index 0000000..e1729f7 --- /dev/null +++ b/cmd/netns/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "git.g3e.fr/syonad/two/internal/netns" +) + +var ( + netns_name = flag.String("netns", "", "Network namespace à faire") + action = flag.String("action", "", "Action a faire") +) + +func main() { + flag.Parse() + + switch *action { + case "create": + err := netns.Create(*netns_name) + if err != nil { + fmt.Println(err) + } + case "delete": + err := netns.Delete(*netns_name) + if err != nil { + fmt.Println(err) + } + case "check": + if netns.Exist(*netns_name) { + fmt.Printf("netns %s exist\n", *netns_name) + } else { + fmt.Printf("netns %s do not exist\n", *netns_name) + } + default: + fmt.Printf("Available commande:\n - create\n - delete\n - check\n") + os.Exit(1) + } +} From d1559b2ba070400ce6fadd0efe80d36b1ba7623e Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 8 Jan 2026 23:58:31 +0100 Subject: [PATCH 46/71] f-10: ci: change ci format #10 Signed-off-by: GnomeZworc --- .forgejo/workflows/prerelease.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index 0248db4..42d3a75 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -32,7 +32,12 @@ jobs: matrix: goos: [linux] goarch: [amd64] - binaries: [db, metadata, metacli, agent, netns] + binaries: + - db + - metadata + - metacli + - agent + - netns uses: ./.forgejo/workflows/build.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} From fc62d5a524e50de92270c92ad657900c43366cf1 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 11 Jan 2026 18:37:31 +0100 Subject: [PATCH 47/71] f-14: package: add a new package Signed-off-by: GnomeZworc --- go.mod | 2 ++ go.sum | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/go.mod b/go.mod index 26bd137..7430e72 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,8 @@ require ( github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.21.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/vishvananda/netlink v1.3.1 // indirect + github.com/vishvananda/netns v0.0.5 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel v1.37.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect diff --git a/go.sum b/go.sum index 0d19489..73d16f3 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,10 @@ github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= +github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= +github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= +github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= @@ -51,6 +55,8 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= From 15a913643edab26206c4a444691150edb79022ea Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 11 Jan 2026 18:38:02 +0100 Subject: [PATCH 48/71] f-14: code: add a new package internal #14 Signed-off-by: GnomeZworc --- internal/netif/veth.go | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 internal/netif/veth.go diff --git a/internal/netif/veth.go b/internal/netif/veth.go new file mode 100644 index 0000000..0056c60 --- /dev/null +++ b/internal/netif/veth.go @@ -0,0 +1,48 @@ +package netif + +import ( + "fmt" + "runtime" + + "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" +) + +func CreateVethToNetns(rootIf, nsIf, netnsPath string, mtu int) error { + // Obligatoire : netns lié au thread + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + // Ouvrir le netns cible + ns, err := netns.GetFromPath(netnsPath) + if err != nil { + return fmt.Errorf("open netns: %w, %s", err, netnsPath) + } + defer ns.Close() + + // Créer le veth dans le netns courant + veth := &netlink.Veth{ + LinkAttrs: netlink.LinkAttrs{ + Name: rootIf, + MTU: mtu, + }, + PeerName: nsIf, + } + + if err := netlink.LinkAdd(veth); err != nil { + return fmt.Errorf("link add: %w", err) + } + + // Récupérer l'interface peer + peer, err := netlink.LinkByName(nsIf) + if err != nil { + return fmt.Errorf("peer not found: %w", err) + } + + // Déplacer le peer dans le netns cible + if err := netlink.LinkSetNsFd(peer, int(ns)); err != nil { + return fmt.Errorf("set ns: %w", err) + } + + return nil +} From 5a38e09b85dbca1b228e94de0f13671eae26d4ec Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 11 Jan 2026 18:38:59 +0100 Subject: [PATCH 49/71] f-14: bin: add a new binarie for test #14 Signed-off-by: GnomeZworc --- cmd/vpc/main.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 cmd/vpc/main.go diff --git a/cmd/vpc/main.go b/cmd/vpc/main.go new file mode 100644 index 0000000..d18dabd --- /dev/null +++ b/cmd/vpc/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "git.g3e.fr/syonad/two/internal/netif" +) + +var ( + netns = flag.String("netns", "", "Network namespace à faire") + name = flag.String("name", "", "interface name") + action = flag.String("action", "", "Action a faire") +) + +func main() { + flag.Parse() + + switch *action { + case "create": + err := netif.CreateVethToNetns("veth"+*name+"ext", "veth"+*name+"int", "/var/run/netns/"+*netns, 9000) + if err != nil { + fmt.Println(err) + } + default: + fmt.Printf("Available commande:\n - create\n - delete\n - check\n") + os.Exit(1) + } +} From 9420a9f7b4e881fbeeda3769592391f4ab49dcfc Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Tue, 13 Jan 2026 10:53:43 +0100 Subject: [PATCH 50/71] f-14: code: add create bridge code #14 Signed-off-by: GnomeZworc --- internal/netif/bridge.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 internal/netif/bridge.go diff --git a/internal/netif/bridge.go b/internal/netif/bridge.go new file mode 100644 index 0000000..d6dea70 --- /dev/null +++ b/internal/netif/bridge.go @@ -0,0 +1,38 @@ +package netif + +import ( + "fmt" + "os" + + "github.com/vishvananda/netlink" +) + +func setBridgeSTP(bridge string, enable bool) error { + path := fmt.Sprintf("/sys/class/net/%s/bridge/stp_state", bridge) + + val := "0" + if enable { + val = "1" + } + + return os.WriteFile(path, []byte(val), 0644) +} + +func CreateBridge(name string, mtu int, stp bool) error { + br := &netlink.Bridge{ + LinkAttrs: netlink.LinkAttrs{ + Name: name, + MTU: mtu, + }, + } + + if err := netlink.LinkAdd(br); err != nil { + return err + } + + if err := netlink.LinkSetUp(br); err != nil { + return err + } + + return setBridgeSTP(name, stp) +} From fd4c7e9a3a6133c0f8f547d65a0b5239a3a63ca3 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Thu, 15 Jan 2026 22:54:22 +0100 Subject: [PATCH 51/71] f-14: code: add an up and down ip #14 Signed-off-by: GnomeZworc --- internal/netif/upDown.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 internal/netif/upDown.go diff --git a/internal/netif/upDown.go b/internal/netif/upDown.go new file mode 100644 index 0000000..6d27cc2 --- /dev/null +++ b/internal/netif/upDown.go @@ -0,0 +1,21 @@ +package netif + +import ( + "github.com/vishvananda/netlink" +) + +func LinkSetUp(name string) error { + link, err := netlink.LinkByName(name) + if err != nil { + return err + } + return netlink.LinkSetUp(link) +} + +func LinkSetDown(name string) error { + link, err := netlink.LinkByName(name) + if err != nil { + return err + } + return netlink.LinkSetDown(link) +} From db222b383cd9b4b17e5676e3dd507ccb27a1fe70 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Fri, 16 Jan 2026 22:15:23 +0100 Subject: [PATCH 52/71] f-14: code: add delete interface function #14 Signed-off-by: GnomeZworc --- internal/netif/delete.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 internal/netif/delete.go diff --git a/internal/netif/delete.go b/internal/netif/delete.go new file mode 100644 index 0000000..9b06c55 --- /dev/null +++ b/internal/netif/delete.go @@ -0,0 +1,13 @@ +package netif + +import ( + "github.com/vishvananda/netlink" +) + +func DeleteLink(name string) error { + link, err := netlink.LinkByName(name) + if err != nil { + return err + } + return netlink.LinkDel(link) +} From d3b471b24aefe303c98dae259c5e44719e65cf56 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sat, 17 Jan 2026 20:59:05 +0100 Subject: [PATCH 53/71] f-14: code: add set master bridge #14 Signed-off-by: GnomeZworc --- internal/netif/bridge.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/netif/bridge.go b/internal/netif/bridge.go index d6dea70..daf21ec 100644 --- a/internal/netif/bridge.go +++ b/internal/netif/bridge.go @@ -36,3 +36,17 @@ func CreateBridge(name string, mtu int, stp bool) error { return setBridgeSTP(name, stp) } + +func BridgeSetMaster(iface, bridge string) error { + link, err := netlink.LinkByName(iface) + if err != nil { + return err + } + + br, err := netlink.LinkByName(bridge) + if err != nil { + return err + } + + return netlink.LinkSetMaster(link, br) +} From 9fb4d10d270c1ea50a9dc11dabd67d20c90dc374 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 18 Jan 2026 22:28:38 +0100 Subject: [PATCH 54/71] f-14: code: add create and delete vpc #14 Signed-off-by: GnomeZworc --- internal/vpc/create.go | 60 ++++++++++++++++++++++++++++++++++++++++++ internal/vpc/delete.go | 18 +++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 internal/vpc/create.go create mode 100644 internal/vpc/delete.go diff --git a/internal/vpc/create.go b/internal/vpc/create.go new file mode 100644 index 0000000..55896ba --- /dev/null +++ b/internal/vpc/create.go @@ -0,0 +1,60 @@ +package vpc + +import ( + "git.g3e.fr/syonad/two/internal/netif" + "git.g3e.fr/syonad/two/internal/netns" +) + +func CreateVPC(name string) error { + // missing + // search data in db + // change state in db + + // create netns + if err := netns.Create(name); err != nil { + return err + } + + // create veth public for this netns + if err := netif.CreateVethToNetns(name+"-ext", "veth-"+name+"-int", "/var/run/netns/"+name, 9000); err != nil { + return err + } + + // create public bridge in netns + if err := netns.Call(name, func() error { + return netif.CreateBridge("br-public", 1500, false) + }); err != nil { + return err + } + + // set veth to ext public bridge + if err := netif.BridgeSetMaster(name+"-ext", "br-public"); err != nil { + return err + } + + // set veth to int public bridge + if err := netns.Call(name, func() error { + return netif.BridgeSetMaster("veth-"+name+"-int", "br-public") + }); err != nil { + return err + } + + // set set ext veth up + if err := netif.LinkSetUp(name + "-ext"); err != nil { + return nil + } + // set set int veth up + if err := netns.Call(name, func() error { + return netif.LinkSetUp("veth-" + name + "-int") + }); err != nil { + return err + } + // set set int bridge up + if err := netns.Call(name, func() error { + return netif.LinkSetUp("br-public") + }); err != nil { + return err + } + + return nil +} diff --git a/internal/vpc/delete.go b/internal/vpc/delete.go new file mode 100644 index 0000000..3daea61 --- /dev/null +++ b/internal/vpc/delete.go @@ -0,0 +1,18 @@ +package vpc + +import ( + "git.g3e.fr/syonad/two/internal/netif" + "git.g3e.fr/syonad/two/internal/netns" +) + +func DeleteVPC(name string) error { + if err := netif.DeleteLink(name + "-ext"); err != nil { + return err + } + + if err := netns.Delete(name); err != nil { + return err + } + + return nil +} From d050568638e6bd5642a2d3dcb494a9f8984f7a01 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 18 Jan 2026 22:30:38 +0100 Subject: [PATCH 55/71] f-14: bin: update bin #14 Signed-off-by: GnomeZworc --- cmd/vpc/main.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/vpc/main.go b/cmd/vpc/main.go index d18dabd..6d70f79 100644 --- a/cmd/vpc/main.go +++ b/cmd/vpc/main.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "git.g3e.fr/syonad/two/internal/netif" + "git.g3e.fr/syonad/two/internal/vpc" ) var ( @@ -19,8 +19,11 @@ func main() { switch *action { case "create": - err := netif.CreateVethToNetns("veth"+*name+"ext", "veth"+*name+"int", "/var/run/netns/"+*netns, 9000) - if err != nil { + if err := vpc.CreateVPC(*name); err != nil { + fmt.Println(err) + } + case "delete": + if err := vpc.DeleteVPC(*name); err != nil { fmt.Println(err) } default: From 0b797d1c0c3c2389aa581122a3bed9e1bebd6e6a Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 18 Jan 2026 22:32:21 +0100 Subject: [PATCH 56/71] f-14: bin: remove netns bin #14 Signed-off-by: GnomeZworc --- .forgejo/workflows/prerelease.yml | 1 - cmd/netns/main.go | 40 ------------------------------- 2 files changed, 41 deletions(-) delete mode 100644 cmd/netns/main.go diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index 42d3a75..ee046e2 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -37,7 +37,6 @@ jobs: - metadata - metacli - agent - - netns uses: ./.forgejo/workflows/build.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} diff --git a/cmd/netns/main.go b/cmd/netns/main.go deleted file mode 100644 index e1729f7..0000000 --- a/cmd/netns/main.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "git.g3e.fr/syonad/two/internal/netns" -) - -var ( - netns_name = flag.String("netns", "", "Network namespace à faire") - action = flag.String("action", "", "Action a faire") -) - -func main() { - flag.Parse() - - switch *action { - case "create": - err := netns.Create(*netns_name) - if err != nil { - fmt.Println(err) - } - case "delete": - err := netns.Delete(*netns_name) - if err != nil { - fmt.Println(err) - } - case "check": - if netns.Exist(*netns_name) { - fmt.Printf("netns %s exist\n", *netns_name) - } else { - fmt.Printf("netns %s do not exist\n", *netns_name) - } - default: - fmt.Printf("Available commande:\n - create\n - delete\n - check\n") - os.Exit(1) - } -} From 6f40b3e9219bdc6f1d34a466fae5dd062d35b038 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Sun, 18 Jan 2026 22:32:49 +0100 Subject: [PATCH 57/71] f-14: code: add vpc in prerelease bin #14 Signed-off-by: GnomeZworc --- .forgejo/workflows/prerelease.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index ee046e2..f20ca66 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -37,6 +37,7 @@ jobs: - metadata - metacli - agent + - vpc uses: ./.forgejo/workflows/build.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} From 2ea3c6dd14ba65e99e902747356d608b422ef4e5 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 19 Jan 2026 22:41:39 +0100 Subject: [PATCH 58/71] f-14: fix: rename interface name Signed-off-by: GnomeZworc --- internal/vpc/create.go | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/internal/vpc/create.go b/internal/vpc/create.go index 55896ba..5ff5fa5 100644 --- a/internal/vpc/create.go +++ b/internal/vpc/create.go @@ -16,42 +16,36 @@ func CreateVPC(name string) error { } // create veth public for this netns - if err := netif.CreateVethToNetns(name+"-ext", "veth-"+name+"-int", "/var/run/netns/"+name, 9000); err != nil { + if err := netif.CreateVethToNetns("veth"+name+"ext", "vethpublicint", "/var/run/netns/"+name, 9000); err != nil { return err } // create public bridge in netns if err := netns.Call(name, func() error { - return netif.CreateBridge("br-public", 1500, false) + return netif.CreateBridge("br-public", 1500) }); err != nil { return err } // set veth to ext public bridge - if err := netif.BridgeSetMaster(name+"-ext", "br-public"); err != nil { + if err := netif.BridgeSetMaster("veth"+name+"ext", "br-public"); err != nil { return err } // set veth to int public bridge if err := netns.Call(name, func() error { - return netif.BridgeSetMaster("veth-"+name+"-int", "br-public") + return netif.BridgeSetMaster("vethpublicint", "br-public") }); err != nil { return err } // set set ext veth up - if err := netif.LinkSetUp(name + "-ext"); err != nil { + if err := netif.LinkSetUp("veth" + name + "ext"); err != nil { return nil } // set set int veth up if err := netns.Call(name, func() error { - return netif.LinkSetUp("veth-" + name + "-int") - }); err != nil { - return err - } - // set set int bridge up - if err := netns.Call(name, func() error { - return netif.LinkSetUp("br-public") + return netif.LinkSetUp("vethpublicint") }); err != nil { return err } From 44f01c23735da8c6e97e2f30072bd8ad6fbbd11e Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 19 Jan 2026 22:42:13 +0100 Subject: [PATCH 59/71] f-14: clean: remove not used setBridgeSTP Signed-off-by: GnomeZworc --- internal/netif/bridge.go | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/internal/netif/bridge.go b/internal/netif/bridge.go index daf21ec..a4754a3 100644 --- a/internal/netif/bridge.go +++ b/internal/netif/bridge.go @@ -1,24 +1,10 @@ package netif import ( - "fmt" - "os" - "github.com/vishvananda/netlink" ) -func setBridgeSTP(bridge string, enable bool) error { - path := fmt.Sprintf("/sys/class/net/%s/bridge/stp_state", bridge) - - val := "0" - if enable { - val = "1" - } - - return os.WriteFile(path, []byte(val), 0644) -} - -func CreateBridge(name string, mtu int, stp bool) error { +func CreateBridge(name string, mtu int) error { br := &netlink.Bridge{ LinkAttrs: netlink.LinkAttrs{ Name: name, @@ -34,7 +20,7 @@ func CreateBridge(name string, mtu int, stp bool) error { return err } - return setBridgeSTP(name, stp) + return nil } func BridgeSetMaster(iface, bridge string) error { From f9c1cd7d328f13df2c0574691b0eaae46fba24c4 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 26 Jan 2026 20:10:56 +0100 Subject: [PATCH 60/71] f-14: code: add db usage in vpc creation #14 Signed-off-by: GnomeZworc --- cmd/vpc/main.go | 26 ++++++++++++--- internal/vpc/create.go | 73 +++++++++++++++++++++++------------------- 2 files changed, 62 insertions(+), 37 deletions(-) diff --git a/cmd/vpc/main.go b/cmd/vpc/main.go index 6d70f79..8f98a46 100644 --- a/cmd/vpc/main.go +++ b/cmd/vpc/main.go @@ -5,21 +5,39 @@ import ( "fmt" "os" + configuration "git.g3e.fr/syonad/two/internal/config/agent" "git.g3e.fr/syonad/two/internal/vpc" + "git.g3e.fr/syonad/two/pkg/db/kv" + "github.com/dgraph-io/badger/v4" ) var ( - netns = flag.String("netns", "", "Network namespace à faire") - name = flag.String("name", "", "interface name") - action = flag.String("action", "", "Action a faire") + netns = flag.String("netns", "", "Network namespace à faire") + name = flag.String("name", "", "interface name") + action = flag.String("action", "", "Action a faire") + conf_file = flag.String("conf", "/etc/two/agent.yml", "configuration file") ) +var DB *badger.DB + func main() { flag.Parse() + conf, err := configuration.LoadConfig(*conf_file) + if err != nil { + fmt.Println(err) + return + } + + DB = kv.InitDB(kv.Config{ + Path: conf.Database.Path, + }, false) + defer DB.Close() + switch *action { case "create": - if err := vpc.CreateVPC(*name); err != nil { + kv.AddInDB(DB, "vpc/"+*name+"/state", "creating") + if err := vpc.CreateVPC(DB, *name); err != nil { fmt.Println(err) } case "delete": diff --git a/internal/vpc/create.go b/internal/vpc/create.go index 5ff5fa5..3c3ad87 100644 --- a/internal/vpc/create.go +++ b/internal/vpc/create.go @@ -3,52 +3,59 @@ package vpc import ( "git.g3e.fr/syonad/two/internal/netif" "git.g3e.fr/syonad/two/internal/netns" + "git.g3e.fr/syonad/two/pkg/db/kv" + + "github.com/dgraph-io/badger/v4" ) -func CreateVPC(name string) error { +func CreateVPC(db *badger.DB, name string) error { // missing // search data in db // change state in db // create netns - if err := netns.Create(name); err != nil { + if state, err := kv.GetFromDB(db, "vpc/"+name+"/state"); err != nil { return err - } + } else if state == "creating" { + if err := netns.Create(name); err != nil { + return err + } - // create veth public for this netns - if err := netif.CreateVethToNetns("veth"+name+"ext", "vethpublicint", "/var/run/netns/"+name, 9000); err != nil { - return err - } + // create veth public for this netns + if err := netif.CreateVethToNetns("veth"+name+"ext", "vethpublicint", "/var/run/netns/"+name, 9000); err != nil { + return err + } - // create public bridge in netns - if err := netns.Call(name, func() error { - return netif.CreateBridge("br-public", 1500) - }); err != nil { - return err - } + // create public bridge in netns + if err := netns.Call(name, func() error { + return netif.CreateBridge("br-public", 1500) + }); err != nil { + return err + } - // set veth to ext public bridge - if err := netif.BridgeSetMaster("veth"+name+"ext", "br-public"); err != nil { - return err - } + // set veth to ext public bridge + if err := netif.BridgeSetMaster("veth"+name+"ext", "br-public"); err != nil { + return err + } - // set veth to int public bridge - if err := netns.Call(name, func() error { - return netif.BridgeSetMaster("vethpublicint", "br-public") - }); err != nil { - return err - } + // set veth to int public bridge + if err := netns.Call(name, func() error { + return netif.BridgeSetMaster("vethpublicint", "br-public") + }); err != nil { + return err + } - // set set ext veth up - if err := netif.LinkSetUp("veth" + name + "ext"); err != nil { - return nil + // set set ext veth up + if err := netif.LinkSetUp("veth" + name + "ext"); err != nil { + return nil + } + // set set int veth up + if err := netns.Call(name, func() error { + return netif.LinkSetUp("vethpublicint") + }); err != nil { + return err + } + kv.AddInDB(db, "vpc/"+name+"/state", "created") } - // set set int veth up - if err := netns.Call(name, func() error { - return netif.LinkSetUp("vethpublicint") - }); err != nil { - return err - } - return nil } From 0b9714ce10d5a445b653f39fa2cdd6384ced86c3 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Tue, 27 Jan 2026 22:24:47 +0100 Subject: [PATCH 61/71] f-14: code: add delete operation #14 Signed-off-by: GnomeZworc --- cmd/vpc/main.go | 9 ++++++++- internal/vpc/delete.go | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/cmd/vpc/main.go b/cmd/vpc/main.go index 8f98a46..52d8133 100644 --- a/cmd/vpc/main.go +++ b/cmd/vpc/main.go @@ -41,9 +41,16 @@ func main() { fmt.Println(err) } case "delete": - if err := vpc.DeleteVPC(*name); err != nil { + kv.AddInDB(DB, "vpc/"+*name+"/state", "deleting") + if err := vpc.DeleteVPC(DB, *name); err != nil { fmt.Println(err) } + if state, err := kv.GetFromDB(DB, "vpc/"+*name+"/state"); err != nil { + fmt.Println(err) + os.Exit(1) + } else if state == "deleted" { + kv.DeleteInDB(DB, "vpc/"+*name) + } default: fmt.Printf("Available commande:\n - create\n - delete\n - check\n") os.Exit(1) diff --git a/internal/vpc/delete.go b/internal/vpc/delete.go index 3daea61..a05e807 100644 --- a/internal/vpc/delete.go +++ b/internal/vpc/delete.go @@ -3,15 +3,23 @@ package vpc import ( "git.g3e.fr/syonad/two/internal/netif" "git.g3e.fr/syonad/two/internal/netns" + "git.g3e.fr/syonad/two/pkg/db/kv" + + "github.com/dgraph-io/badger/v4" ) -func DeleteVPC(name string) error { - if err := netif.DeleteLink(name + "-ext"); err != nil { +func DeleteVPC(db *badger.DB, name string) error { + if state, err := kv.GetFromDB(db, "vpc/"+name+"/state"); err != nil { return err - } + } else if state == "deleting" { + if err := netif.DeleteLink(name + "-ext"); err != nil { + return err + } - if err := netns.Delete(name); err != nil { - return err + if err := netns.Delete(name); err != nil { + return err + } + kv.AddInDB(db, "vpc/"+name+"/state", "deleted") } return nil From 88787fd8f7ad3f86dafe118eaa65461bf6dc6bfc Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 23 Mar 2026 18:24:06 +0100 Subject: [PATCH 62/71] f-14: code: add check feature Signed-off-by: GnomeZworc --- cmd/vpc/main.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/vpc/main.go b/cmd/vpc/main.go index 52d8133..58e4242 100644 --- a/cmd/vpc/main.go +++ b/cmd/vpc/main.go @@ -51,6 +51,12 @@ func main() { } else if state == "deleted" { kv.DeleteInDB(DB, "vpc/"+*name) } + case "check": + if state, err := kv.GetFromDB(DB, "vpc/"+*name+"/state"); err != nil { + os.Exit(1) + } else if state == "created" { + os.Exit(1) + } default: fmt.Printf("Available commande:\n - create\n - delete\n - check\n") os.Exit(1) From c1b9b3faa4131b27c094ca03079962f3643fb258 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Tue, 24 Mar 2026 20:24:37 +0100 Subject: [PATCH 63/71] f-14: fix: add return code Signed-off-by: GnomeZworc --- cmd/vpc/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/vpc/main.go b/cmd/vpc/main.go index 58e4242..708054c 100644 --- a/cmd/vpc/main.go +++ b/cmd/vpc/main.go @@ -61,4 +61,5 @@ func main() { fmt.Printf("Available commande:\n - create\n - delete\n - check\n") os.Exit(1) } + os.Exit(0) } From d3402dd163c7c277617b566b2aba68604ac96a0e Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Tue, 24 Mar 2026 20:28:49 +0100 Subject: [PATCH 64/71] f-14: fix: change return code Signed-off-by: GnomeZworc --- cmd/vpc/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/vpc/main.go b/cmd/vpc/main.go index 708054c..e73f7e9 100644 --- a/cmd/vpc/main.go +++ b/cmd/vpc/main.go @@ -54,7 +54,7 @@ func main() { case "check": if state, err := kv.GetFromDB(DB, "vpc/"+*name+"/state"); err != nil { os.Exit(1) - } else if state == "created" { + } else if state != "created" { os.Exit(1) } default: From 5d980514b8ea66d06d2052aa0837be6ddc4850f7 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 30 Mar 2026 23:16:52 +0200 Subject: [PATCH 65/71] f-15: code: add generate dhcp file Signed-off-by: GnomeZworc --- internal/dhcp/generate.go | 47 +++++++++++++++++++++++++++++++++++++++ internal/dhcp/struct.go | 12 ++++++++++ 2 files changed, 59 insertions(+) create mode 100644 internal/dhcp/generate.go create mode 100644 internal/dhcp/struct.go diff --git a/internal/dhcp/generate.go b/internal/dhcp/generate.go new file mode 100644 index 0000000..01bfe20 --- /dev/null +++ b/internal/dhcp/generate.go @@ -0,0 +1,47 @@ +package dhcp + +import ( + "fmt" + "net" + "os" + "path/filepath" + "strings" +) + +func GenerateConfig(c Config) (string, error) { + mask := fmt.Sprintf("%d.%d.%d.%d", c.Network.Mask[0], c.Network.Mask[1], c.Network.Mask[2], c.Network.Mask[3]) + + var sb strings.Builder + fmt.Fprintf(&sb, "no-resolv\n") + fmt.Fprintf(&sb, "dhcp-range=%s,static,%s,12h\n", c.Network.IP.String(), mask) + fmt.Fprintf(&sb, "dhcp-option=3,%s\n", c.Gateway.String()) + fmt.Fprintf(&sb, "dhcp-option=6,1.1.1.1,8.8.8.8\n\n") + + i := 0 + for ip := cloneIP(c.Network.IP); c.Network.Contains(ip); incrementIP(ip) { + fmt.Fprintf(&sb, "dhcp-host=00:22:33:%02X:%02X:%02X,%s\n", + (i>>16)&0xFF, (i>>8)&0xFF, i&0xFF, ip) + i++ + } + + outPath := filepath.Join(c.ConfDir, c.Name+".conf") + if err := os.MkdirAll(c.ConfDir, 0755); err != nil { + return "", err + } + return outPath, os.WriteFile(outPath, []byte(sb.String()), 0644) +} + +func incrementIP(ip net.IP) { + for j := len(ip) - 1; j >= 0; j-- { + ip[j]++ + if ip[j] != 0 { + break + } + } +} + +func cloneIP(ip net.IP) net.IP { + clone := make(net.IP, len(ip)) + copy(clone, ip) + return clone +} diff --git a/internal/dhcp/struct.go b/internal/dhcp/struct.go new file mode 100644 index 0000000..4c69b9c --- /dev/null +++ b/internal/dhcp/struct.go @@ -0,0 +1,12 @@ +package dhcp + +import ( + "net" +) + +type Config struct { + Network *net.IPNet + Gateway net.IP + Name string + ConfDir string +} From a346876cfb8e308d2e3aed526b01f0bb173ea67e Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 30 Mar 2026 23:19:34 +0200 Subject: [PATCH 66/71] f-15: code add code for binary Signed-off-by: GnomeZworc --- cmd/dhcp/main.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 cmd/dhcp/main.go diff --git a/cmd/dhcp/main.go b/cmd/dhcp/main.go new file mode 100644 index 0000000..b2ce08d --- /dev/null +++ b/cmd/dhcp/main.go @@ -0,0 +1,64 @@ +package main + +import ( + "flag" + "fmt" + "net" + "os" + + "git.g3e.fr/syonad/two/internal/dhcp" + "git.g3e.fr/syonad/two/pkg/systemd" +) + +func main() { + subnet := flag.String("subnet", "", "Subnet CIDR (e.g. 10.10.10.0/24)") + name := flag.String("name", "", "Config name (e.g. vpc1_br-00002)") + gateway := flag.String("gateway", "", "Gateway IP (e.g. 10.10.10.1)") + confDir := flag.String("confdir", "/etc/dnsmasq.d", "dnsmasq config directory") + flag.Parse() + + if *subnet == "" || *name == "" || *gateway == "" { + flag.Usage() + os.Exit(1) + } + + _, network, err := net.ParseCIDR(*subnet) + if err != nil { + fmt.Fprintf(os.Stderr, "invalid subnet: %v\n", err) + os.Exit(1) + } + + gw := net.ParseIP(*gateway) + if gw == nil { + fmt.Fprintf(os.Stderr, "invalid gateway IP: %q\n", *gateway) + os.Exit(1) + } + + conf := dhcp.Config{ + Network: network, + Gateway: gw, + Name: *name, + ConfDir: *confDir, + } + + confPath, err := dhcp.GenerateConfig(conf) + if err != nil { + fmt.Fprintf(os.Stderr, "error generating config: %v\n", err) + os.Exit(1) + } + fmt.Printf("dnsmasq config written to %s\n", confPath) + + svc, err := systemd.New() + if err != nil { + fmt.Fprintf(os.Stderr, "error connecting to systemd: %v\n", err) + os.Exit(1) + } + defer svc.Close() + + unit := "dnsmasq@" + *name + ".service" + if err := svc.Start(unit); err != nil { + fmt.Fprintf(os.Stderr, "error starting %s: %v\n", unit, err) + os.Exit(1) + } + fmt.Printf("started %s\n", unit) +} From cfbac0034b5ab9e73b975d55282a58d142d6f8f5 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 30 Mar 2026 23:20:24 +0200 Subject: [PATCH 67/71] f-15: ci: add dhcp binary build Signed-off-by: GnomeZworc --- .forgejo/workflows/prerelease.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index f20ca66..8b2fe2d 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -38,6 +38,7 @@ jobs: - metacli - agent - vpc + - dhcp uses: ./.forgejo/workflows/build.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} @@ -51,4 +52,4 @@ jobs: uses: ./.forgejo/workflows/release.yml with: tag: ${{ needs.set-release-target.outputs.release_cible }} - secrets: inherit \ No newline at end of file + secrets: inherit From 02e558e0e2cc59b7768117ef299f507cc5d7bf64 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 30 Mar 2026 23:20:51 +0200 Subject: [PATCH 68/71] f-15: systemd: add systemd unit for dhcp Signed-off-by: GnomeZworc --- systemd/dnsmasq@.service | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 systemd/dnsmasq@.service diff --git a/systemd/dnsmasq@.service b/systemd/dnsmasq@.service new file mode 100644 index 0000000..0f9d72e --- /dev/null +++ b/systemd/dnsmasq@.service @@ -0,0 +1,11 @@ +[Unit] +Description=dnsmasq in netns %i +After=network.target + +[Service] +Type=simple +ExecStart=/opt/two/bin/run-dnsmasq-in-netns.sh %i +ExecStopPost=/bin/rm -f /run/dnsmasq-%i.pid + +[Install] +WantedBy=multi-user.target From deac1afe9fd1230dfa1d3a598ec54c2dcb47db78 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 30 Mar 2026 23:21:27 +0200 Subject: [PATCH 69/71] f-15: script: add script for running dhcp in netns Signed-off-by: GnomeZworc --- scripts/run-dnsmasq-in-netns.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 scripts/run-dnsmasq-in-netns.sh diff --git a/scripts/run-dnsmasq-in-netns.sh b/scripts/run-dnsmasq-in-netns.sh new file mode 100644 index 0000000..c0f9253 --- /dev/null +++ b/scripts/run-dnsmasq-in-netns.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +# Expects one argument: netns_bridge (e.g. vpc-00003_br-00002 or vpc1_br0) +arg="$1" +NETNS="${arg%%_*}" +BRIDGE="${arg#*_}" + +echo "start dnsmasq ${NETNS} ${BRIDGE}" + +exec ip netns exec "${NETNS}" \ + dnsmasq \ + --no-daemon \ + --interface="${BRIDGE}" \ + --bind-interfaces \ + --pid-file="/run/dnsmasq-$arg.pid" \ + --conf-file="/etc/dnsmasq.d/$arg.conf" \ + --no-hosts \ + --no-resolv \ + --log-facility="/var/log/dnsmasq-$arg.log" \ + --no-daemon -p0 From 3288a2a413e35379185e80d992564117ac5e1a5a Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Mon, 30 Mar 2026 23:30:18 +0200 Subject: [PATCH 70/71] f-15: ci: add upload scripts Signed-off-by: GnomeZworc --- .forgejo/workflows/prerelease.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml index 8b2fe2d..f9b8a43 100644 --- a/.forgejo/workflows/prerelease.yml +++ b/.forgejo/workflows/prerelease.yml @@ -46,6 +46,24 @@ jobs: goarch: ${{ matrix.goarch }} binari: ${{ matrix.binaries }} secrets: inherit + upload-scripts: + runs-on: docker + needs: [set-release-target] + strategy: + matrix: + script: + - run-dnsmasq-in-netns.sh + steps: + - uses: actions/checkout@v3 + - name: Move asset + run: | + mkdir -p "dist" + cp scripts/${{ matrix.script }} dist/ + - name: Upload script + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.script }}-${{ needs.set-release-target.outputs.release_cible }} + path: dist/${{ matrix.script }} prerelease: runs-on: docker needs: [set-release-target, build] From c7d20b412429b7976b5f9257a3b8e4bdc6d2bbe1 Mon Sep 17 00:00:00 2001 From: GnomeZworc Date: Tue, 31 Mar 2026 20:03:52 +0200 Subject: [PATCH 71/71] f-19: test: ajouter des test Signed-off-by: GnomeZworc --- internal/config/agent/config_test.go | 83 +++++++++++ internal/dhcp/dhcp_test.go | 157 +++++++++++++++++++++ internal/metadata/metadata_test.go | 200 +++++++++++++++++++++++++++ pkg/db/kv/kv_test.go | 153 ++++++++++++++++++++ 4 files changed, 593 insertions(+) create mode 100644 internal/config/agent/config_test.go create mode 100644 internal/dhcp/dhcp_test.go create mode 100644 internal/metadata/metadata_test.go create mode 100644 pkg/db/kv/kv_test.go diff --git a/internal/config/agent/config_test.go b/internal/config/agent/config_test.go new file mode 100644 index 0000000..d0f3d31 --- /dev/null +++ b/internal/config/agent/config_test.go @@ -0,0 +1,83 @@ +package configuration + +import ( + "os" + "path/filepath" + "testing" +) + +func writeYAML(t *testing.T, content string) string { + t.Helper() + path := filepath.Join(t.TempDir(), "config.yml") + if err := os.WriteFile(path, []byte(content), 0644); err != nil { + t.Fatalf("impossible d'écrire le fichier de config : %v", err) + } + return path +} + +// --- LoadConfig --- + +func TestLoadConfig_ValidFile(t *testing.T) { + path := writeYAML(t, ` +database: + path: /tmp/mydb +`) + cfg, err := LoadConfig(path) + if err != nil { + t.Fatalf("LoadConfig a échoué : %v", err) + } + if cfg.Database.Path != "/tmp/mydb" { + t.Errorf("database.path attendu %q, obtenu %q", "/tmp/mydb", cfg.Database.Path) + } +} + +func TestLoadConfig_DefaultPath(t *testing.T) { + // Fichier vide → viper applique la valeur par défaut + path := writeYAML(t, "") + cfg, err := LoadConfig(path) + if err != nil { + t.Fatalf("LoadConfig a échoué : %v", err) + } + if cfg.Database.Path != "/var/lib/two/data/" { + t.Errorf("valeur par défaut attendue %q, obtenu %q", "/var/lib/two/data/", cfg.Database.Path) + } +} + +func TestLoadConfig_MissingFile_UsesDefaults(t *testing.T) { + // Fichier inexistant : viper ignore l'erreur ReadInConfig et retourne les défauts + cfg, err := LoadConfig("/chemin/inexistant/config.yml") + if err != nil { + t.Fatalf("LoadConfig devrait retourner les défauts si le fichier est absent : %v", err) + } + if cfg.Database.Path != "/var/lib/two/data/" { + t.Errorf("valeur par défaut attendue, obtenu %q", cfg.Database.Path) + } +} + +func TestLoadConfig_PartialConfig_MissingDatabaseKey(t *testing.T) { + // Fichier sans la clé database → valeur par défaut + path := writeYAML(t, ` +autrekey: valeur +`) + cfg, err := LoadConfig(path) + if err != nil { + t.Fatalf("LoadConfig a échoué : %v", err) + } + if cfg.Database.Path != "/var/lib/two/data/" { + t.Errorf("valeur par défaut attendue, obtenu %q", cfg.Database.Path) + } +} + +func TestLoadConfig_CustomPath(t *testing.T) { + path := writeYAML(t, ` +database: + path: /opt/two/data +`) + cfg, err := LoadConfig(path) + if err != nil { + t.Fatalf("LoadConfig a échoué : %v", err) + } + if cfg.Database.Path != "/opt/two/data" { + t.Errorf("attendu %q, obtenu %q", "/opt/two/data", cfg.Database.Path) + } +} diff --git a/internal/dhcp/dhcp_test.go b/internal/dhcp/dhcp_test.go new file mode 100644 index 0000000..c4a659f --- /dev/null +++ b/internal/dhcp/dhcp_test.go @@ -0,0 +1,157 @@ +package dhcp + +import ( + "net" + "os" + "path/filepath" + "strings" + "testing" +) + +func parseNet(t *testing.T, cidr string) *net.IPNet { + t.Helper() + _, network, err := net.ParseCIDR(cidr) + if err != nil { + t.Fatalf("ParseCIDR(%q) : %v", cidr, err) + } + return network +} + +// --- cloneIP --- + +func TestCloneIP_IsIndependent(t *testing.T) { + ip := net.ParseIP("10.0.0.1").To4() + clone := cloneIP(ip) + clone[3] = 99 + if ip[3] == 99 { + t.Error("cloneIP devrait retourner une copie indépendante") + } +} + +// --- incrementIP --- + +func TestIncrementIP_Simple(t *testing.T) { + ip := net.ParseIP("10.0.0.1").To4() + incrementIP(ip) + if ip.String() != "10.0.0.2" { + t.Errorf("attendu 10.0.0.2, obtenu %s", ip) + } +} + +func TestIncrementIP_Carry(t *testing.T) { + ip := net.ParseIP("10.0.0.255").To4() + incrementIP(ip) + if ip.String() != "10.0.1.0" { + t.Errorf("attendu 10.0.1.0, obtenu %s", ip) + } +} + +// --- GenerateConfig --- + +func newConf(t *testing.T, cidr string) Config { + t.Helper() + _, network, _ := net.ParseCIDR(cidr) + return Config{ + Network: network, + Gateway: net.ParseIP("192.168.1.1").To4(), + Name: "test", + ConfDir: t.TempDir(), + } +} + +func TestGenerateConfig_CreatesFile(t *testing.T) { + conf := newConf(t, "192.168.1.0/29") // 6 hôtes + path, err := GenerateConfig(conf) + if err != nil { + t.Fatalf("GenerateConfig a échoué : %v", err) + } + + if _, err := os.Stat(path); os.IsNotExist(err) { + t.Errorf("le fichier %q n'a pas été créé", path) + } +} + +func TestGenerateConfig_FilenameMatchesName(t *testing.T) { + conf := newConf(t, "192.168.1.0/29") + path, err := GenerateConfig(conf) + if err != nil { + t.Fatalf("GenerateConfig a échoué : %v", err) + } + + expected := filepath.Join(conf.ConfDir, "test.conf") + if path != expected { + t.Errorf("chemin attendu %q, obtenu %q", expected, path) + } +} + +func TestGenerateConfig_ContainsGateway(t *testing.T) { + conf := newConf(t, "192.168.1.0/29") + path, _ := GenerateConfig(conf) + content, _ := os.ReadFile(path) + + if !strings.Contains(string(content), "dhcp-option=3,192.168.1.1") { + t.Errorf("gateway absente du fichier généré :\n%s", content) + } +} + +func TestGenerateConfig_ContainsDhcpRange(t *testing.T) { + _, network, _ := net.ParseCIDR("10.10.0.0/24") + conf := Config{ + Network: network, + Gateway: net.ParseIP("10.10.0.1").To4(), + Name: "vpc1", + ConfDir: t.TempDir(), + } + path, _ := GenerateConfig(conf) + content, _ := os.ReadFile(path) + + if !strings.Contains(string(content), "dhcp-range=10.10.0.0,static,255.255.255.0,12h") { + t.Errorf("dhcp-range absent ou incorrect :\n%s", content) + } +} + +func TestGenerateConfig_OneHostEntryPerIP(t *testing.T) { + // /29 = réseau + broadcast + 6 hôtes → 8 adresses + conf := newConf(t, "10.0.0.0/29") + path, _ := GenerateConfig(conf) + content, _ := os.ReadFile(path) + + lines := strings.Split(string(content), "\n") + count := 0 + for _, l := range lines { + if strings.HasPrefix(l, "dhcp-host=") { + count++ + } + } + // /29 contient 8 adresses (0 à 7) + if count != 8 { + t.Errorf("attendu 8 entrées dhcp-host, obtenu %d", count) + } +} + +func TestGenerateConfig_MACPrefix(t *testing.T) { + conf := newConf(t, "10.0.0.0/30") // 4 adresses + path, _ := GenerateConfig(conf) + content, _ := os.ReadFile(path) + + if !strings.Contains(string(content), "00:22:33:") { + t.Errorf("préfixe MAC 00:22:33: absent :\n%s", content) + } +} + +func TestGenerateConfig_CreatesConfDir(t *testing.T) { + dir := filepath.Join(t.TempDir(), "sous", "dossier") + _, network, _ := net.ParseCIDR("10.0.0.0/30") + conf := Config{ + Network: network, + Gateway: net.ParseIP("10.0.0.1").To4(), + Name: "net", + ConfDir: dir, + } + if _, err := GenerateConfig(conf); err != nil { + t.Fatalf("GenerateConfig devrait créer les répertoires manquants : %v", err) + } + if _, err := os.Stat(dir); os.IsNotExist(err) { + t.Errorf("répertoire %q non créé", dir) + } +} diff --git a/internal/metadata/metadata_test.go b/internal/metadata/metadata_test.go new file mode 100644 index 0000000..62a2830 --- /dev/null +++ b/internal/metadata/metadata_test.go @@ -0,0 +1,200 @@ +package metadata + +import ( + "strings" + "testing" + + "git.g3e.fr/syonad/two/pkg/db/kv" +) + +func newCfg() NoCloudConfig { + return NoCloudConfig{ + VpcName: "vpc-test", + BindIP: "169.254.169.254", + BindPort: "80", + Name: "vm1", + Password: "s3cr3t", + SSHKEY: "ssh-ed25519 AAAA... user@host", + } +} + +func newTestDB(t *testing.T) interface{ Close() error } { + t.Helper() + db := kv.InitDB(kv.Config{Path: t.TempDir()}, false) + t.Cleanup(func() { db.Close() }) + return db +} + +// --- RenderConfig --- + +func TestRenderConfig_MetaData(t *testing.T) { + cfg := newCfg() + out, err := RenderConfig("templates/meta-data.tmpl", cfg) + if err != nil { + t.Fatalf("RenderConfig meta-data : %v", err) + } + if !strings.Contains(out, "instance-id: vm1") { + t.Errorf("instance-id absent :\n%s", out) + } + if !strings.Contains(out, "local-hostname: vm1") { + t.Errorf("local-hostname absent :\n%s", out) + } +} + +func TestRenderConfig_VendorData_ContainsPassword(t *testing.T) { + cfg := newCfg() + out, err := RenderConfig("templates/vendor-data.tmpl", cfg) + if err != nil { + t.Fatalf("RenderConfig vendor-data : %v", err) + } + if !strings.Contains(out, "s3cr3t") { + t.Errorf("password absent du vendor-data :\n%s", out) + } +} + +func TestRenderConfig_VendorData_ContainsSSHKey(t *testing.T) { + cfg := newCfg() + out, err := RenderConfig("templates/vendor-data.tmpl", cfg) + if err != nil { + t.Fatalf("RenderConfig vendor-data : %v", err) + } + if !strings.Contains(out, "ssh-ed25519 AAAA... user@host") { + t.Errorf("clé SSH absente du vendor-data :\n%s", out) + } +} + +func TestRenderConfig_NetworkConfig(t *testing.T) { + cfg := newCfg() + out, err := RenderConfig("templates/network-config.tmpl", cfg) + if err != nil { + t.Fatalf("RenderConfig network-config : %v", err) + } + if !strings.Contains(out, "dhcp4: true") { + t.Errorf("dhcp4 absent du network-config :\n%s", out) + } +} + +func TestRenderConfig_UserData(t *testing.T) { + cfg := newCfg() + out, err := RenderConfig("templates/user-data.tmpl", cfg) + if err != nil { + t.Fatalf("RenderConfig user-data : %v", err) + } + if !strings.Contains(out, "passwd -d root") { + t.Errorf("user-data inattendu :\n%s", out) + } +} + +func TestRenderConfig_InvalidTemplate(t *testing.T) { + _, err := RenderConfig("templates/inexistant.tmpl", newCfg()) + if err == nil { + t.Error("RenderConfig devrait retourner une erreur pour un template inexistant") + } +} + +func TestRenderConfig_SpecialCharsInName(t *testing.T) { + cfg := newCfg() + cfg.Name = "vm-prod-01" + out, err := RenderConfig("templates/meta-data.tmpl", cfg) + if err != nil { + t.Fatalf("RenderConfig : %v", err) + } + if !strings.Contains(out, "vm-prod-01") { + t.Errorf("nom vm-prod-01 absent :\n%s", out) + } +} + +// --- LoadNcCloudInDB / UnLoadNoCloudInDB --- + +func TestLoadNcCloudInDB_StoresAllKeys(t *testing.T) { + db := kv.InitDB(kv.Config{Path: t.TempDir()}, false) + t.Cleanup(func() { db.Close() }) + + cfg := newCfg() + LoadNcCloudInDB(cfg, db) + + keys := []string{ + "metadata/vm1/meta-data", + "metadata/vm1/user-data", + "metadata/vm1/network-config", + "metadata/vm1/vendor-data", + "metadata/vm1/vpc", + "metadata/vm1/bind_ip", + "metadata/vm1/bind_port", + } + for _, key := range keys { + val, err := kv.GetFromDB(db, key) + if err != nil { + t.Errorf("clé %q absente après LoadNcCloudInDB : %v", key, err) + } + if val == "" && key != "metadata/vm1/user-data" { + t.Errorf("clé %q vide après LoadNcCloudInDB", key) + } + } +} + +func TestLoadNcCloudInDB_VpcAndBindValues(t *testing.T) { + db := kv.InitDB(kv.Config{Path: t.TempDir()}, false) + t.Cleanup(func() { db.Close() }) + + cfg := newCfg() + LoadNcCloudInDB(cfg, db) + + vpc, _ := kv.GetFromDB(db, "metadata/vm1/vpc") + if vpc != "vpc-test" { + t.Errorf("vpc attendu %q, obtenu %q", "vpc-test", vpc) + } + + ip, _ := kv.GetFromDB(db, "metadata/vm1/bind_ip") + if ip != "169.254.169.254" { + t.Errorf("bind_ip attendu %q, obtenu %q", "169.254.169.254", ip) + } + + port, _ := kv.GetFromDB(db, "metadata/vm1/bind_port") + if port != "80" { + t.Errorf("bind_port attendu %q, obtenu %q", "80", port) + } +} + +func TestUnLoadNoCloudInDB_RemovesAllKeys(t *testing.T) { + db := kv.InitDB(kv.Config{Path: t.TempDir()}, false) + t.Cleanup(func() { db.Close() }) + + cfg := newCfg() + LoadNcCloudInDB(cfg, db) + UnLoadNoCloudInDB("vm1", db) + + keys := []string{ + "metadata/vm1/meta-data", + "metadata/vm1/user-data", + "metadata/vm1/network-config", + "metadata/vm1/vendor-data", + "metadata/vm1/vpc", + "metadata/vm1/bind_ip", + "metadata/vm1/bind_port", + } + for _, key := range keys { + _, err := kv.GetFromDB(db, key) + if err == nil { + t.Errorf("clé %q devrait être supprimée après UnLoadNoCloudInDB", key) + } + } +} + +func TestUnLoadNoCloudInDB_DoesNotAffectOtherVMs(t *testing.T) { + db := kv.InitDB(kv.Config{Path: t.TempDir()}, false) + t.Cleanup(func() { db.Close() }) + + cfg1 := newCfg() + cfg2 := newCfg() + cfg2.Name = "vm2" + LoadNcCloudInDB(cfg1, db) + LoadNcCloudInDB(cfg2, db) + + UnLoadNoCloudInDB("vm1", db) + + _, err := kv.GetFromDB(db, "metadata/vm2/vpc") + if err != nil { + t.Errorf("vm2 ne devrait pas être supprimée : %v", err) + } +} diff --git a/pkg/db/kv/kv_test.go b/pkg/db/kv/kv_test.go new file mode 100644 index 0000000..de4fd68 --- /dev/null +++ b/pkg/db/kv/kv_test.go @@ -0,0 +1,153 @@ +package kv + +import ( + "errors" + "testing" + + "github.com/dgraph-io/badger/v4" +) + +// newTestDB ouvre une base BadgerDB dans un répertoire temporaire. +// La base est fermée automatiquement en fin de test. +func newTestDB(t *testing.T) *badger.DB { + t.Helper() + db := InitDB(Config{Path: t.TempDir()}, false) + t.Cleanup(func() { db.Close() }) + return db +} + +// --- InitDB --- + +func TestInitDB_ValidPath(t *testing.T) { + db := newTestDB(t) + if db == nil { + t.Fatal("InitDB devrait retourner une DB non-nil") + } +} + +func TestInitDB_InvalidPath_Panics(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fatal("InitDB avec un chemin invalide devrait paniquer") + } + }() + InitDB(Config{Path: "/chemin/inexistant/absolu"}, false) +} + +// --- AddInDB --- + +func TestAddInDB_NewKey(t *testing.T) { + db := newTestDB(t) + if err := AddInDB(db, "vpc/test", "valeur"); err != nil { + t.Fatalf("AddInDB a échoué : %v", err) + } +} + +func TestAddInDB_OverwriteExistingKey(t *testing.T) { + db := newTestDB(t) + AddInDB(db, "vpc/test", "premiere") + if err := AddInDB(db, "vpc/test", "deuxieme"); err != nil { + t.Fatalf("AddInDB (écrasement) a échoué : %v", err) + } + + val, _ := GetFromDB(db, "vpc/test") + if val != "deuxieme" { + t.Errorf("valeur attendue %q, obtenu %q", "deuxieme", val) + } +} + +// --- GetFromDB --- + +func TestGetFromDB_ExistingKey(t *testing.T) { + db := newTestDB(t) + AddInDB(db, "vpc/foo", "bar") + + val, err := GetFromDB(db, "vpc/foo") + if err != nil { + t.Fatalf("GetFromDB a échoué : %v", err) + } + if val != "bar" { + t.Errorf("valeur attendue %q, obtenu %q", "bar", val) + } +} + +func TestGetFromDB_MissingKey(t *testing.T) { + db := newTestDB(t) + + _, err := GetFromDB(db, "inexistant") + if !errors.Is(err, badger.ErrKeyNotFound) { + t.Errorf("erreur attendue ErrKeyNotFound, obtenu : %v", err) + } +} + +func TestGetFromDB_EmptyValue(t *testing.T) { + db := newTestDB(t) + AddInDB(db, "vpc/vide", "") + + val, err := GetFromDB(db, "vpc/vide") + if err != nil { + t.Fatalf("GetFromDB a échoué : %v", err) + } + if val != "" { + t.Errorf("valeur attendue vide, obtenu %q", val) + } +} + +// --- DeleteInDB --- + +func TestDeleteInDB_SimpleKey(t *testing.T) { + db := newTestDB(t) + AddInDB(db, "vpc/a", "v") + + if err := DeleteInDB(db, "vpc/a"); err != nil { + t.Fatalf("DeleteInDB a échoué : %v", err) + } + + _, err := GetFromDB(db, "vpc/a") + if !errors.Is(err, badger.ErrKeyNotFound) { + t.Errorf("la clé devrait être supprimée, obtenu : %v", err) + } +} + +func TestDeleteInDB_WithSubkeys(t *testing.T) { + db := newTestDB(t) + // Clé parente + sous-clés (préfixe "vpc/net1/") + AddInDB(db, "vpc/net1", "parent") + AddInDB(db, "vpc/net1/ip", "10.0.0.1") + AddInDB(db, "vpc/net1/gw", "10.0.0.254") + + if err := DeleteInDB(db, "vpc/net1"); err != nil { + t.Fatalf("DeleteInDB a échoué : %v", err) + } + + for _, key := range []string{"vpc/net1", "vpc/net1/ip", "vpc/net1/gw"} { + _, err := GetFromDB(db, key) + if !errors.Is(err, badger.ErrKeyNotFound) { + t.Errorf("clé %q devrait être supprimée, obtenu : %v", key, err) + } + } +} + +func TestDeleteInDB_DoesNotDeleteSiblings(t *testing.T) { + db := newTestDB(t) + AddInDB(db, "vpc/net1", "a") + AddInDB(db, "vpc/net2", "b") // ne doit pas être supprimée + + DeleteInDB(db, "vpc/net1") + + val, err := GetFromDB(db, "vpc/net2") + if err != nil { + t.Fatalf("vpc/net2 ne devrait pas être supprimée : %v", err) + } + if val != "b" { + t.Errorf("valeur attendue %q, obtenu %q", "b", val) + } +} + +func TestDeleteInDB_MissingKey(t *testing.T) { + db := newTestDB(t) + // Supprimer une clé inexistante ne doit pas crasher + if err := DeleteInDB(db, "inexistant"); err != nil { + t.Logf("DeleteInDB clé inexistante retourne : %v (non bloquant)", err) + } +}