From 99912cfaccff984f43e36eb88a600878540ca1ba Mon Sep 17 00:00:00 2001 From: Truong Nguyen Date: Fri, 24 Jan 2025 17:26:48 -0800 Subject: [PATCH 1/3] add windows bundle, dockerfile, and start ps script --- Dockerfile.windows | 15 ++++++ bundle-windows.yml | 101 +++++++++++++++++++++++++++++++++++++++ downloader.go | 116 +++++++++++++++++++++++++++++++++++++++++++-- start.ps1 | 39 +++++++++++++++ 4 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 Dockerfile.windows create mode 100644 bundle-windows.yml create mode 100644 start.ps1 diff --git a/Dockerfile.windows b/Dockerfile.windows new file mode 100644 index 00000000..3aba7fe6 --- /dev/null +++ b/Dockerfile.windows @@ -0,0 +1,15 @@ +FROM mcr.microsoft.com/windows/servercore:ltsc2019 + +WORKDIR C:\\newrelic + +COPY out\\amd64 C:\\newrelic +COPY ./start.ps1 C:\\newrelic + +# ENV NEW_RELIC_LICENSE_KEY="" +# ENV NEW_RELIC_APP_NAME="" + +# RUN powershell.exe -File "C:\\newrelic\\Program Files\\New Relic\\newrelic-infra\\installer.ps1" + +COPY start.ps1 C:\\newrelic\\start.ps1 + +ENTRYPOINT ["powershell.exe", "-File", "C:\\newrelic\\start.ps1"] \ No newline at end of file diff --git a/bundle-windows.yml b/bundle-windows.yml new file mode 100644 index 00000000..aa537efd --- /dev/null +++ b/bundle-windows.yml @@ -0,0 +1,101 @@ +# Version of the base agent image to use (`newrelic/infrastructure). +# This is used by the `docker-build.sh` wrapper if AGENT_VERSION is not set +agentVersion: 1.60.1 + +# url, stagingUrl, and repo fields are compiled as templates. The `trimv` helper function can be used to remove the leading v +# from a version string. + +# Used as defaults for all integrations below, can be overridden. Template. +# url: https://download.newrelic.com/infrastructure_agent/binaries/linux/{{.Arch}}/{{.Name}}_linux_{{.Version | trimv}}_{{.Arch}}.tar.gz +url: https://download.newrelic.com/infrastructure_agent/binaries/windows/{{.Arch}}/{{.Name}}-{{.Arch}}.{{.Version | trimv}}.zip + +# stagingUrl will be used if the download is invoked with -staging. Template. +# stagingUrl: https://github.com/newrelic/{{.Name}}/releases/download/{{.Version}}/{{.Name}}_linux_{{.Version | trimv}}_{{.Arch}}.tar.gz + +# List of architectures to fetch. +# archs: [ amd64, arm, arm64 ] +archs: [ amd64 ] +# GitHub repo hosting the integration. Used to fetch the latest available version when using -latest. Template. +repo: newrelic/{{.Name}} + +# List of files to check for existence after integration has been unpacked. Template. +testFiles: + # Test for existence of the main integation binary + # - /var/db/newrelic-infra/newrelic-integrations/bin/{{.Name}}.exe + - /New Relic/newrelic-infra/newrelic-integrations/bin/{{.Name}}.exe + + # - C:\\ProgramFiles\\New Relic\\newrelic-infra\\newrelic-integrations\\bin\\{{.Name}}.exe + +# List of integrations to download. +# Individual entries may override any of the values defined above. +integrations: +# - name: nri-apache +# version: 1.5.0 +# +# subpath: "" # Custom path to extract archive into. By default, it is assumed that the integration tarball is structured to be extracted in `/`. +# archReplacements: # Used as a key->value replacement when making the current arch from []archs available in {{.Arch}}. Useful for sketchy naming schemes. +# amd64: x86_64 +# +# # Overrides: +# archs: [] # Bundle this integration only in the specified architectures. +# url: "" # Defaults to global `url`, useful if tarballs have odd naming schemes. +# stagingUrl: "" # Defaults to global `stagingUrl`. +# repo: "" # Defaults to global `repo`. + - name: newrelic-infra + version: v1.60.1 + testFiles: + - /Program Files/New Relic/newrelic-infra/ + - name: nri-apache + version: v1.13.2 + - name: nri-cassandra + version: v2.14.1 + - name: nri-consul + version: v2.8.3 + - name: nri-couchbase + version: v2.7.2 + - name: nri-elasticsearch + version: v5.4.0 + - name: nri-f5 + version: v2.8.1 + - name: nri-haproxy + version: v3.1.0 + - name: nri-jmx + version: v3.7.2 + # testFiles: + # - /opt/newrelic-infra/newrelic-integrations/bin/nri-jmx + + - name: nri-kafka + version: v3.10.0 + - name: nri-memcached + version: v2.6.2 + - name: nri-mongodb + version: v2.9.2 + - name: nri-mysql + version: v1.12.0 + - name: nri-nagios + version: v2.10.1 + - name: nri-nginx + version: v3.5.1 + - name: nri-postgresql + version: v2.16.1 + - name: nri-rabbitmq + version: v2.14.1 + - name: nri-redis + version: v1.12.1 + # - name: nrjmx + # version: v2.6.0 + # url: https://download.newrelic.com/infrastructure_agent/binaries/windows/noarch/nrjmx_windows_{{.Version | trimv}}_noarch.zip + # # stagingUrl: https://github.com/newrelic/{{.Name}}/releases/download/{{.Version}}/nrjmx_linux_{{.Version | trimv}}_noarch.tar.gz + # testFiles: + # - /New Relic/newrelic-infra/newrelic-integrations/Program Files/New Relic/nrjmx/bin/nrjmx + - name: nri-discovery-kubernetes + version: v1.10.0 + url: https://github.com/newrelic/{{.Name}}/releases/download/{{.Version}}/{{.Name}}-amd64.{{.Version | trimv}}.zip + stagingUrl: https://github.com/newrelic/{{.Name}}/releases/download/{{.Version}}/{{.Name}}_{{.Version | trimv}}_Linux_{{.Arch}}.tar.gz + subpath: var/db/newrelic-infra + archReplacements: + amd64: x86_64 + testFiles: + - /var/db/newrelic-infra/nri-discovery-kubernetes.exe + - name: nri-mssql + version: v2.16.0 diff --git a/downloader.go b/downloader.go index cbf3d970..09f2c9ad 100644 --- a/downloader.go +++ b/downloader.go @@ -1,10 +1,12 @@ package main import ( + "archive/zip" "bytes" "context" "flag" "fmt" + "io" "io/fs" "log" "net/http" @@ -12,6 +14,7 @@ import ( "os/exec" "path" "path/filepath" + "runtime" "sort" "strings" "sync" @@ -64,7 +67,14 @@ func main() { checkLatest := flag.Bool("check-latest", false, "check for new versions and exit") flag.Parse() + isWindows := false + if runtime.GOOS == "windows" { + isWindows = true + fmt.Println("Running on windows...") + } + bundleFile, err := os.Open(*bfname) + fmt.Println("zzzbundleFile", bundleFile) if err != nil { log.Fatal(err) } @@ -96,7 +106,7 @@ func main() { if err := conf.expand(*staging, *overrideLatest || *checkLatest); err != nil { log.Fatal(err) } - + fmt.Print("%=v\n", conf) // Print new versions and exit. if *checkLatest { conf.printUpdates() @@ -134,7 +144,7 @@ func main() { wg.Wait() log.Printf("Preparing tree for install...") - if err := prepareTree(*outdir); err != nil { + if err := prepareTree(*outdir, isWindows); err != nil { log.Fatal(err) } @@ -355,6 +365,25 @@ func (i *integration) download(outdir string) error { } log.Printf("Downloading and extracting %s (%s)", i.Name, arch) + + isZip := false + if strings.HasSuffix(strings.ToLower(url), ".zip") { + isZip = true + err = extractZip(response.Body, destination) + } else { + err = extractTarGz(response.Body, destination) + } + + if err != nil { + extension := "" + if isZip { + extension = ".zip" + } else { + extension = ".tar.gz" + } + return fmt.Errorf("failed to extract %s file: %w", extension, err) + } + // Invoke tar externally with pipe (simplifies code). cmd := exec.Command("tar", "-xz") cmd.Dir = destination @@ -370,6 +399,78 @@ func (i *integration) download(outdir string) error { return nil } +func extractZip(body io.Reader, destination string) error { + tmpFile, err := os.CreateTemp("", "download-*.zip") + + if err != nil { + return fmt.Errorf("failed to create temp file: %w", err) + } + + defer os.Remove(tmpFile.Name()) + defer tmpFile.Close() + + if _, err := io.Copy(tmpFile, body); err != nil { + return fmt.Errorf("failed to save zip content : %w", err) + } + + reader, err := zip.OpenReader(tmpFile.Name()) + if err != nil { + return fmt.Errorf("failed to open zip: %w", err) + } + defer reader.Close() + + for _, file := range reader.File { + err := extractZipFile(file, destination) + if err != nil { + return fmt.Errorf("failed to extract %s: %w", file.Name, err) + } + } + + return nil +} + +func extractZipFile(file *zip.File, destination string) error { + path := filepath.Join(destination, file.Name) + + //Check for ZipSlip. More Info: https://snyk.io/research/zip-slip-vulnerability + if !strings.HasPrefix(path, filepath.Clean(destination)+string(os.PathSeparator)) { + return fmt.Errorf(">invalid file path: %s", path) + } + + if file.FileInfo().IsDir() { + return os.MkdirAll(path, file.Mode()) + } + + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + + dst, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) + if err != nil { + return err + } + defer dst.Close() + + src, err := file.Open() + if err != nil { + return err + } + defer src.Close() + + _, err = io.Copy(dst, src) + return err +} + +func extractTarGz(body io.Reader, destination string) error { + cmd := exec.Command("tar", "-xz") + cmd.Dir = destination + cmd.Stdin = body + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + + return cmd.Run() +} + // overrideVersion fetches the tag name of the latest release (or prerelease) from Github func (i *integration) overrideVersion(gh *github.Client, includePrereleases bool) error { // Evaluate repo template @@ -458,7 +559,7 @@ func oauthClientFromEnv() *http.Client { } // prepareTree cleans up *.sample and windows-related files -func prepareTree(outdir string) error { +func prepareTree(outdir string, isWindows bool) error { return filepath.Walk(outdir, func(path string, info fs.FileInfo, err error) error { if info.IsDir() { return nil // Continue @@ -468,7 +569,14 @@ func prepareTree(outdir string) error { return os.Remove(path) } - for _, pattern := range []string{"-win-", "README", "CHANGELOG", "LICENSE"} { + platformToRemove := "" + if isWindows { + platformToRemove = "-linux-" + } else { + platformToRemove = "-win-" + } + + for _, pattern := range []string{platformToRemove, "README", "CHANGELOG", "LICENSE"} { if strings.Contains(info.Name(), pattern) { return os.Remove(path) } diff --git a/start.ps1 b/start.ps1 new file mode 100644 index 00000000..bdca68e2 --- /dev/null +++ b/start.ps1 @@ -0,0 +1,39 @@ +. "C:\newrelic\Program Files\New Relic\newrelic-infra\installer.ps1" + + +net start newrelic-infra + +# Start-Process "C:\newrelic\Program Files/New Relic/newrelic-infra/newrelic-infra-service.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-apache.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-cassandra.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-consul.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-couchbase.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-elasticsearch.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-f5.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-haproxy.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-jmx.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-kafka.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-memcached.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-mongodb.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-mssql.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-mysql.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-nagios.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-nginx.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-postgresql.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-rabbitmq.exe" +# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-redis.exe" + + + +# Start-Process "C:\newrelic\Program Files\New relic\nrjmx\bin\nrjmx.bat" + +# Start-Process "C:\newrelic\var\db\newrelic-infra\nri-discovery-kubernetes.exe" + + + + + + + + +while ($true) { Start-Sleep -Seconds 60} \ No newline at end of file From 89638cd99ac1b6676c5eee65bd9c39d4646c83f6 Mon Sep 17 00:00:00 2001 From: Truong Nguyen Date: Tue, 4 Feb 2025 08:35:28 -0800 Subject: [PATCH 2/3] update start.ps1 --- Dockerfile.windows | 1 + start.ps1 | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Dockerfile.windows b/Dockerfile.windows index 3aba7fe6..c17af704 100644 --- a/Dockerfile.windows +++ b/Dockerfile.windows @@ -12,4 +12,5 @@ COPY ./start.ps1 C:\\newrelic COPY start.ps1 C:\\newrelic\\start.ps1 +USER ContainerAdministrator ENTRYPOINT ["powershell.exe", "-File", "C:\\newrelic\\start.ps1"] \ No newline at end of file diff --git a/start.ps1 b/start.ps1 index bdca68e2..d7fff25f 100644 --- a/start.ps1 +++ b/start.ps1 @@ -1,9 +1,30 @@ -. "C:\newrelic\Program Files\New Relic\newrelic-infra\installer.ps1" +# // Runs installer in a new scope +& "C:\newrelic\Program Files\New Relic\newrelic-infra\installer.ps1" +$service = Start-Service -Name "newrelic-infra" -PassThru -net start newrelic-infra +if ($service.Status -ne 'Running') { + Write-Error "Failed to start newrelic-infra service" + exit 1 +} -# Start-Process "C:\newrelic\Program Files/New Relic/newrelic-infra/newrelic-infra-service.exe" +# $process = Start-Process -FilePath "C:\newrelic\Program Files\New Relic\newrelic-infra\newrelic-infra.exe" -PassThru + +# Start-Sleep -Seconds 5 + +# if ($process.) + +# if ($process.HasExited) { +# Write-Error "newrelic-infra.exe process exited unexpectedly" +# exit 1 +# } + + +Write-Output "Neew Relic Infrastructure started successfully" + +# net start newrelic-infra + +# Start-Process "C:\newrelic\Program Files\New Relic\newrelic-infra\newrelic-infra.exe" # Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-apache.exe" # Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-cassandra.exe" # Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-consul.exe" From 336df6cb54250339945ae6c4fb0f27b9f135e670 Mon Sep 17 00:00:00 2001 From: tmnguyen12 Date: Tue, 4 Feb 2025 15:38:56 -0800 Subject: [PATCH 3/3] update start1.ps1 to log .\newrelic-infra.exe --- start.ps1 | 72 ++++++++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/start.ps1 b/start.ps1 index d7fff25f..17355da0 100644 --- a/start.ps1 +++ b/start.ps1 @@ -1,5 +1,6 @@ # // Runs installer in a new scope & "C:\newrelic\Program Files\New Relic\newrelic-infra\installer.ps1" +# & "C:\newrelic\Program Files\New Relic\newrelic-infra\installer.ps1" $service = Start-Service -Name "newrelic-infra" -PassThru @@ -8,53 +9,42 @@ if ($service.Status -ne 'Running') { exit 1 } -# $process = Start-Process -FilePath "C:\newrelic\Program Files\New Relic\newrelic-infra\newrelic-infra.exe" -PassThru +$process = Start-Process -FilePath "C:\Program Files\New Relic\newrelic-infra\newrelic-infra.exe" -PassThru -NoNewWindow -RedirectStandardOutput stdout.log -RedirectStandardError stderr.log -# Start-Sleep -Seconds 5 - -# if ($process.) - -# if ($process.HasExited) { -# Write-Error "newrelic-infra.exe process exited unexpectedly" -# exit 1 -# } - - -Write-Output "Neew Relic Infrastructure started successfully" +if ($process.HasExited) { + Write-Error "newrelic-infra.exe process exited unexpectedly" + exit 1 +} # net start newrelic-infra # Start-Process "C:\newrelic\Program Files\New Relic\newrelic-infra\newrelic-infra.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-apache.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-cassandra.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-consul.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-couchbase.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-elasticsearch.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-f5.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-haproxy.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-jmx.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-kafka.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-memcached.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-mongodb.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-mssql.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-mysql.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-nagios.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-nginx.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-postgresql.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-rabbitmq.exe" -# Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-redis.exe" - - +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-apache.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-cassandra.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-consul.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-couchbase.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-elasticsearch.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-f5.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-haproxy.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-jmx.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-kafka.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-memcached.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-mongodb.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-mssql.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-mysql.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-nagios.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-nginx.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-postgresql.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-rabbitmq.exe" +Start-Process "C:\newrelic\New Relic\newrelic-infra\newrelic-integrations\bin\nri-redis.exe" # Start-Process "C:\newrelic\Program Files\New relic\nrjmx\bin\nrjmx.bat" +Start-Process "C:\newrelic\var\db\newrelic-infra\nri-discovery-kubernetes.exe" -# Start-Process "C:\newrelic\var\db\newrelic-infra\nri-discovery-kubernetes.exe" +Write-Output "zzNew Relic Infrastructure started successfully" - - - - - - - -while ($true) { Start-Sleep -Seconds 60} \ No newline at end of file +while ($true) { + if (Test-Path stdout.log) { Get-Content stdout.log -Wait -Tail 0 } + if (Test-path stderr.log) { Get-Content stderr.log -Wait -Tail 0 } + Start-Sleep -Seconds 60 +}