diff --git a/charts/faker-telemetry-client/.helmignore b/charts/faker-telemetry-client/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/faker-telemetry-client/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/faker-telemetry-client/Chart.yaml b/charts/faker-telemetry-client/Chart.yaml new file mode 100644 index 0000000..7d8eb1b --- /dev/null +++ b/charts/faker-telemetry-client/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: faker-telemetry-client +description: A Helm chart for Kubernetes +type: application +version: 0.1.0 +appVersion: "0.1.0" diff --git a/charts/faker-telemetry-client/templates/_helpers.tpl b/charts/faker-telemetry-client/templates/_helpers.tpl new file mode 100644 index 0000000..7fc608d --- /dev/null +++ b/charts/faker-telemetry-client/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "..name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "..fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "..chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "..labels" -}} +helm.sh/chart: {{ include "..chart" . }} +{{ include "..selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "..selectorLabels" -}} +app.kubernetes.io/name: {{ include "..name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "..serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "..fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/faker-telemetry-client/templates/job.yaml b/charts/faker-telemetry-client/templates/job.yaml new file mode 100644 index 0000000..28a2b94 --- /dev/null +++ b/charts/faker-telemetry-client/templates/job.yaml @@ -0,0 +1,26 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: faker-telemetry-client + labels: + app: faker-telemetry-client +spec: + parallelism: {{ .Values.replicas }} + completions: {{ .Values.replicas }} + template: + metadata: + labels: + app: faker-telemetry-client + spec: + restartPolicy: Never + containers: + - name: telemetry-client + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: SERVER_URL + value: "{{ .Values.env.serverURL }}" + - name: TELEMETRY_PATH + value: "{{ .Values.env.telemetryPath }}" + - name: FILE_COUNT + value: "{{ .Values.replicasFilesCount }}" diff --git a/charts/faker-telemetry-client/values.yaml b/charts/faker-telemetry-client/values.yaml new file mode 100644 index 0000000..e2ec7e7 --- /dev/null +++ b/charts/faker-telemetry-client/values.yaml @@ -0,0 +1,11 @@ +replicas: 1 +replicasFilesCount: 10 + +image: + repository: gbuenodevsuse/telemetry-client + tag: test2 + pullPolicy: Always + +env: + serverURL: "http://telemetry-server:9999/telemetry" + telemetryPath: /app/cmd/faker/fake_telemetry_data diff --git a/cmd/faker/.gitignore b/cmd/faker/.gitignore new file mode 100644 index 0000000..9d7f6e8 --- /dev/null +++ b/cmd/faker/.gitignore @@ -0,0 +1 @@ +faker diff --git a/cmd/faker/Dockerfile b/cmd/faker/Dockerfile new file mode 100644 index 0000000..567f789 --- /dev/null +++ b/cmd/faker/Dockerfile @@ -0,0 +1,8 @@ +FROM registry.suse.com/bci/golang:1.21-openssl + +WORKDIR /app +COPY . . + +RUN mkdir -p /tmp/susetelemetry + +ENTRYPOINT [ "go", "run", "cmd/faker/process/process_files.go" ] \ No newline at end of file diff --git a/cmd/faker/Makefile b/cmd/faker/Makefile new file mode 100644 index 0000000..0b309a5 --- /dev/null +++ b/cmd/faker/Makefile @@ -0,0 +1 @@ +include ../../Makefile.golang diff --git a/cmd/faker/config/client_template.yaml b/cmd/faker/config/client_template.yaml new file mode 100644 index 0000000..b9e897f --- /dev/null +++ b/cmd/faker/config/client_template.yaml @@ -0,0 +1,16 @@ +telemetry_base_url: {{.SERVER_URL}} +enabled: true +customer_id: {{.CUSTOMER_ID}} +tags: [] +datastores: + driver: sqlite3 + params: /tmp/telemetry/client/telemetry.db +logging: + level: debug + location: stderr + style: text +class_options: + opt_out: true + opt_in: false + allow: [] + deny: [] diff --git a/cmd/faker/go.mod b/cmd/faker/go.mod new file mode 100644 index 0000000..1c22057 --- /dev/null +++ b/cmd/faker/go.mod @@ -0,0 +1,5 @@ +module github.com/SUSE/telemetry/cmd/faker + +go 1.21 + +require github.com/brianvoe/gofakeit/v6 v6.28.0 diff --git a/cmd/faker/go.sum b/cmd/faker/go.sum new file mode 100644 index 0000000..7ae018c --- /dev/null +++ b/cmd/faker/go.sum @@ -0,0 +1,2 @@ +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= diff --git a/cmd/faker/main.go b/cmd/faker/main.go new file mode 100644 index 0000000..6addea9 --- /dev/null +++ b/cmd/faker/main.go @@ -0,0 +1,94 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "os" + "path/filepath" + + "github.com/brianvoe/gofakeit/v6" +) + +type TelemetryData struct { + Version int `json:"version"` + Hostname string `json:"hostname"` + DistroTarget string `json:"distroTarget"` + HwInfo HwInfo `json:"hwInfo"` +} + +type HwInfo struct { + Hostname string `json:"hostname"` + CPUs int `json:"cpus"` + Sockets int `json:"sockets"` + Hypervisor string `json:"hypervisor"` + Arch string `json:"arch"` + UUID string `json:"uuid"` + CloudProvider string `json:"cloudProvider"` + MemTotal int `json:"memTotal"` +} + +func GenerateHostName() string { + return fmt.Sprintf("%s-%d", gofakeit.AppName(), gofakeit.Number(1, 9999)) +} + +func GenerateFakeData() TelemetryData { + hostname := GenerateHostName() + return TelemetryData{ + Version: gofakeit.Number(1, 10), + Hostname: hostname, + DistroTarget: fmt.Sprintf("sle-%d-x86_64", gofakeit.Number(12, 15)), + HwInfo: HwInfo{ + Hostname: hostname, + CPUs: gofakeit.Number(1, 64), + Sockets: gofakeit.Number(1, 4), + Hypervisor: gofakeit.RandomString([]string{"KVM", "VMware", "Hyper-V", "Xen", ""}), + Arch: gofakeit.RandomString([]string{"amd64", "arm64", "arm"}), + UUID: gofakeit.UUID(), + CloudProvider: gofakeit.RandomString([]string{"AWS", "Azure", "GCP", "On-Premise", ""}), + MemTotal: gofakeit.Number(1024, 65536), + }, + } +} + +func SaveToJSONFile(data TelemetryData, dir string, index int) (string, error) { + fileName := fmt.Sprintf("telemetry_data_%d.json", index) + filePath := filepath.Join(dir, fileName) + + file, err := os.Create(filePath) + if err != nil { + return "", fmt.Errorf("failed to create file: %w", err) + } + defer file.Close() + + encoder := json.NewEncoder(file) + encoder.SetIndent("", " ") + if err := encoder.Encode(data); err != nil { + return "", fmt.Errorf("failed to encode JSON: %w", err) + } + + return filePath, nil +} + +func main() { + outputDir := flag.String("output", "fake_telemetry_data", "Ouput Directory") + numEntries := flag.Int("count", 30, "Number of fake telemetry entries to generate") + flag.Parse() + + if err := os.MkdirAll(*outputDir, os.ModePerm); err != nil { + fmt.Printf("Failed to create output directory: %s\n", err) + os.Exit(1) + } + + for i := 1; i <= *numEntries; i++ { + data := GenerateFakeData() + filePath, err := SaveToJSONFile(data, *outputDir, i) + if err != nil { + fmt.Printf("Error saving file: %s\n", err) + os.Exit(1) + } + fmt.Printf("Generated file: %s\n", filePath) + } + + fmt.Printf("Generated %d fake telemetry data files in directory: %s\n", *numEntries, *outputDir) +} diff --git a/cmd/faker/process/process_files.go b/cmd/faker/process/process_files.go new file mode 100755 index 0000000..1c235a6 --- /dev/null +++ b/cmd/faker/process/process_files.go @@ -0,0 +1,125 @@ +package main + +import ( + "bytes" + "fmt" + "log" + "math/rand" + "os" + "os/exec" + "path/filepath" + "strconv" + "text/template" +) + +func main() { + // Get the current working directory + currentDir, err := os.Getwd() + if err != nil { + log.Fatalf("Failed to get current working directory: %v", err) + } + baseDir := filepath.Join(currentDir, "cmd", "faker") + + // Read environment variables + clientId := rand.Intn(1000000) // Random client ID as an integer + serverURL := os.Getenv("SERVER_URL") + telemetryPath := os.Getenv("TELEMETRY_PATH") + fileCountStr := os.Getenv("FILE_COUNT") + + if serverURL == "" || telemetryPath == "" || fileCountStr == "" { + log.Fatalf("Missing required environment variables") + } + + fileCount, err := strconv.Atoi(fileCountStr) + if err != nil { + log.Fatalf("Invalid FILE_COUNT: %v", err) + } + + // Load the template config + templatePath := filepath.Join(baseDir, "config", "client_template.yaml") + templateContent, err := os.ReadFile(templatePath) + if err != nil { + log.Fatalf("Failed to read template file: %v", err) + } + + // Parse the template + tmpl, err := template.New("config").Parse(string(templateContent)) + if err != nil { + log.Fatalf("Failed to parse template: %v", err) + } + + // Generate the client-specific config + configData := map[string]interface{}{ + "SERVER_URL": serverURL, + "CUSTOMER_ID": clientId, + } + var configBuffer bytes.Buffer + if err := tmpl.Execute(&configBuffer, configData); err != nil { + log.Fatalf("Failed to execute template: %v", err) + } + + // Save the generated config file + configPath := filepath.Join(baseDir, "config", fmt.Sprintf("client_%d.yaml", clientId)) + if err := os.WriteFile(configPath, configBuffer.Bytes(), 0644); err != nil { + log.Fatalf("Failed to write config file: %v", err) + } + + fmt.Printf("Generated config file: %s\n", configPath) + + // Run the faker command to generate telemetry data + if err := os.Chdir(baseDir); err != nil { + log.Fatalf("Failed to change directory to %s: %v", baseDir, err) + } + + // Run the faker command to generate data + fakerCmd := exec.Command("go", "run", ".", "--count", fileCountStr) + fakerCmd.Stdout = os.Stdout + fakerCmd.Stderr = os.Stderr + fmt.Println("Generating fake telemetry data...") + if err := fakerCmd.Run(); err != nil { + log.Fatalf("Faker command failed: %v", err) + } + fmt.Println("Fake telemetry data generated successfully.") + + // Change to the `cmd/authenticator` directory + authDir := filepath.Join(currentDir, "cmd", "authenticator") + if err := os.Chdir(authDir); err != nil { + log.Fatalf("Failed to change directory to %s: %v", authDir, err) + } + + // Authenticate the client + authCmd := exec.Command("go", "run", ".", "--config", configPath) + authCmd.Stdout = os.Stdout + authCmd.Stderr = os.Stderr + fmt.Println("Authenticating client...") + if err := authCmd.Run(); err != nil { + log.Fatalf("Authentication failed: %v", err) + } + fmt.Println("Client authenticated successfully.") + + // Change back to the telemetry generator directory + genDir := filepath.Join(currentDir, "cmd", "generator") + if err := os.Chdir(genDir); err != nil { + log.Fatalf("Failed to change directory to %s: %v", genDir, err) + } + + // Process telemetry files + for i := 1; i < fileCount; i++ { + file := filepath.Join(telemetryPath, fmt.Sprintf("telemetry_data_%d.json", i)) + if _, err := os.Stat(file); os.IsNotExist(err) { + fmt.Printf("File %s does not exist. Skipping.\n", file) + continue + } + + cmd := exec.Command("go", "run", ".", "--config", configPath, "--telemetry=FAKER-GENERATED-DATA", "--tag=FAKERTEST", file) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + log.Printf("Failed to process file %s: %v", file, err) + } else { + fmt.Printf("Processed file: %s\n", file) + } + } + + fmt.Println("Telemetry submission completed.") +}