diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml new file mode 100644 index 0000000..9cd29e6 --- /dev/null +++ b/.forgejo/workflows/build.yml @@ -0,0 +1,43 @@ +on: + workflow_call: + inputs: + tag: + required: true + type: string + goos: + required: true + type: string + goarch: + required: true + type: string + binari: + required: true + type: string + +jobs: + build: + runs-on: docker + env: + RELEASE_CIBLE: ${{ inputs.tag }} + GOOS: ${{ inputs.goos }} + GOARCH: ${{ inputs.goarch }} + BINARI: ${{ inputs.binari }} + CGO_ENABLED: 0 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v5 + with: + go-version: "1.21" + - name: Build du projet + run: | + echo "Building for ${BINARI}/${GOOS}/${GOARCH} (release: ${RELEASE_CIBLE})" + go env GOOS GOARCH + mkdir -p dist/ + go build -o dist/${BINARI}_${GOOS}_${GOARCH} ./cmd/${BINARI} + echo "artifact pour ${RELEASE_CIBLE} ${BINARI} ${GOOS} ${GOARCH}" > dist/${BINARI}-${GOOS}-${GOARCH}.txt + ls -l ./dist + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ env.BINARI }}-${{ env.RELEASE_CIBLE }}-${{ env.GOOS }}-${{ env.GOARCH }} + path: dist/${{ env.BINARI }}_${{ env.GOOS }}_${{ env.GOARCH }} \ No newline at end of file diff --git a/.forgejo/workflows/prerelease.yml b/.forgejo/workflows/prerelease.yml new file mode 100644 index 0000000..fcb74c6 --- /dev/null +++ b/.forgejo/workflows/prerelease.yml @@ -0,0 +1,49 @@ +name: Pre Release Workflow + +on: + push: + tags: + - '*rc*' + +jobs: + set-release-target: + runs-on: docker + outputs: + release_cible: ${{ steps.setvar.outputs.release_cible }} + steps: + - name: Déterminer la release cible + id: setvar + run: | + if [[ "${GITHUB_REF}" == refs/tags/* ]]; then + TAG="${GITHUB_REF#refs/tags/}" + echo "release_cible=$TAG" >> $GITHUB_OUTPUT + elif [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then + echo "release_cible=latest" >> $GITHUB_OUTPUT + else + echo "release_cible=unknown" >> $GITHUB_OUTPUT + fi + + - name: Afficher la variable + run: echo "Release cible = ${{ steps.setvar.outputs.release_cible }}" + build: + runs-on: docker + needs: [set-release-target] + strategy: + matrix: + goos: [linux] + goarch: [amd64] + binaries: [db, metadata] + uses: ./.forgejo/workflows/build.yml + with: + tag: ${{ needs.set-release-target.outputs.release_cible }} + goos: ${{ matrix.goos }} + goarch: ${{ matrix.goarch }} + binari: ${{ matrix.binaries }} + secrets: inherit + prerelease: + runs-on: docker + needs: [set-release-target, build] + uses: ./.forgejo/workflows/release.yml + with: + tag: ${{ needs.set-release-target.outputs.release_cible }} + secrets: inherit \ No newline at end of file diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml new file mode 100644 index 0000000..efc7694 --- /dev/null +++ b/.forgejo/workflows/release.yml @@ -0,0 +1,56 @@ +on: + workflow_call: + inputs: + tag: + required: true + type: string + +jobs: + release: + runs-on: docker + env: + TOKEN: ${{ secrets.RELEASE }} + TAG: ${{ inputs.tag }} + steps: + - name: Download all build artifacts + uses: actions/download-artifact@v3 + with: + path: dist/ + - name: Publier tous les binaires + run: ls -lR dist/ + - name: Install jq + run: | + apt-get update + apt-get install -y jq + - name: Create prerelease + run: | + curl -X POST \ + -H "Authorization: token $TOKEN" \ + -H "Content-Type: application/json" \ + "https://git.g3e.fr/api/v1/repos/${{ github.repository }}/releases" \ + -d @- < [args...]") + return + } + + cmd := os.Args[1] + + switch cmd { + case "check_in_db": + if len(os.Args) != 4 { + fmt.Println("Usage: check_in_db ") + os.Exit(1) + } + ret := CheckInDB(os.Args[2], os.Args[3]) + os.Exit(ret) + case "add_in_db": + if len(os.Args) < 4 { + fmt.Println("Usage: add_in_db ") + os.Exit(1) + } + line := strings.Join(os.Args[3:], ";") + if err := AddInDB(os.Args[2], line); err != nil { + fmt.Println("Error:", err) + os.Exit(1) + } + case "delete_in_db": + if len(os.Args) != 4 { + fmt.Println("Usage: delete_in_db ") + os.Exit(1) + } + if err := DeleteInDB(os.Args[2], os.Args[3]); err != nil { + fmt.Println("Error:", err) + os.Exit(1) + } + case "count_in_db": + if len(os.Args) != 4 { + fmt.Println("Usage: count_in_db ") + os.Exit(1) + } + count := CountInDB(os.Args[2], os.Args[3]) + fmt.Println(count) + case "get_from_db": + if len(os.Args) != 4 { + fmt.Println("Usage: get_from_db ") + os.Exit(1) + } + line, _ := GetFromDB(os.Args[2], os.Args[3]) + fmt.Println(line) + case "print": + printDB() + os.Exit(1) + default: + fmt.Println("Unknown command:", cmd) + os.Exit(1) + } +} diff --git a/cmd/metadata/main.go b/cmd/metadata/main.go new file mode 100644 index 0000000..54bae88 --- /dev/null +++ b/cmd/metadata/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "git.g3e.fr/syonad/two/internal/metadata" +) + +func main() { + metadata.StartServer() +} diff --git a/exemple/agent/config.exemple.yml b/exemple/agent/config.exemple.yml new file mode 100644 index 0000000..a2b9f1b --- /dev/null +++ b/exemple/agent/config.exemple.yml @@ -0,0 +1,2 @@ +database: + path: "/var/lib/two/data/" \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cbc34b5 --- /dev/null +++ b/go.mod @@ -0,0 +1,33 @@ +module git.g3e.fr/syonad/two + +go 1.23.8 + +require ( + github.com/cespare/xxhash/v2 v2.3.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 + github.com/fsnotify/fsnotify v1.9.0 // indirect + 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/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 + github.com/sagikazarmark/locafero v0.11.0 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/spf13/viper v1.21.0 // indirect + github.com/subosito/gotenv v1.6.0 // 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 + 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/text v0.28.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2482f6c --- /dev/null +++ b/go.sum @@ -0,0 +1,56 @@ +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/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= +github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +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/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= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +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= +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= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +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.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +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= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/.keep b/internal/.keep new file mode 100644 index 0000000..e69de29 diff --git a/internal/config/agent/struct.go b/internal/config/agent/struct.go new file mode 100644 index 0000000..12a46d3 --- /dev/null +++ b/internal/config/agent/struct.go @@ -0,0 +1,30 @@ +package configuration + +import ( + "github.com/spf13/viper" +) + +type Config struct { + Database struct { + Path string `mapstructure:"path"` + } `mapstructure:"database"` +} + +func LoadConfig(path string) (*Config, error) { + v := viper.New() + v.SetConfigFile(path) + v.SetConfigType("yaml") + + v.SetDefault("database.path", "/var/lib/two/data/") + + if err := v.ReadInConfig(); err != nil { + return nil, err + } + + var cfg Config + if err := v.Unmarshal(&cfg); err != nil { + return nil, err + } + + return &cfg, nil +} diff --git a/internal/metadata/server.go b/internal/metadata/server.go new file mode 100644 index 0000000..336f754 --- /dev/null +++ b/internal/metadata/server.go @@ -0,0 +1,75 @@ +package metadata + +import ( + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "net" + "net/http" + "time" +) + +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") +) + +func getIP(r *http.Request) string { + ip, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + return r.RemoteAddr + } + return ip +} + +func rootHandler(w http.ResponseWriter, r *http.Request) { + ip := getIP(r) + path := r.URL.Path + timestamp := time.Now().Format(time.RFC3339) + userAgent := r.Header.Get("User-Agent") + + log.Printf("[%s] Requête IP %s vers %s | User-Agent: %s", timestamp, ip, path, userAgent) + + w.Header().Set("Content-Type", "text/yaml") + + switch path { + case "/user-data": + fmt.Fprint(w, data.UserData) + case "/meta-data": + fmt.Fprint(w, data.MetaData) + case "/network-config": + fmt.Fprint(w, data.NetworkConfig) + case "/vendor-data": + fmt.Fprint(w, data.VendorData) + default: + http.NotFound(w, r) + } +} + +func StartServer() { + flag.Parse() + + if *file == "" { + log.Fatal("Vous devez spécifier un fichier via --file") + } + + raw, err := ioutil.ReadFile(*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", *iface, *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 new file mode 100644 index 0000000..f1edf18 --- /dev/null +++ b/internal/metadata/struct.go @@ -0,0 +1,8 @@ +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"` +} diff --git a/pkg/.keep b/pkg/.keep new file mode 100644 index 0000000..e69de29 diff --git a/pkg/db/kv/init.go b/pkg/db/kv/init.go new file mode 100644 index 0000000..18148df --- /dev/null +++ b/pkg/db/kv/init.go @@ -0,0 +1,19 @@ +package kv + +import ( + "github.com/dgraph-io/badger/v4" +) + +func InitDB(conf Config) *badger.DB { + opts := badger.DefaultOptions(conf.Path) + opts.Logger = nil + opts.ValueLogFileSize = 10 << 20 // 10 Mo par fichier vlog + opts.NumMemtables = 1 + opts.NumLevelZeroTables = 1 + opts.NumLevelZeroTablesStall = 2 + db, err := badger.Open(opts) + if err != nil { + panic(err) + } + return db +} diff --git a/pkg/db/kv/struct.go b/pkg/db/kv/struct.go new file mode 100644 index 0000000..71b195f --- /dev/null +++ b/pkg/db/kv/struct.go @@ -0,0 +1,5 @@ +package kv + +type Config struct { + Path string +}