Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

WIP: add windows bundle, dockerfile, and start ps script #485

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Dockerfile.windows
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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

USER ContainerAdministrator
ENTRYPOINT ["powershell.exe", "-File", "C:\\newrelic\\start.ps1"]
101 changes: 101 additions & 0 deletions bundle-windows.yml
Original file line number Diff line number Diff line change
@@ -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
116 changes: 112 additions & 4 deletions downloader.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package main

import (
"archive/zip"
"bytes"
"context"
"flag"
"fmt"
"io"
"io/fs"
"log"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
}
Expand Down
50 changes: 50 additions & 0 deletions start.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# // 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

if ($service.Status -ne 'Running') {
Write-Error "Failed to start newrelic-infra service"
exit 1
}

$process = Start-Process -FilePath "C:\Program Files\New Relic\newrelic-infra\newrelic-infra.exe" -PassThru -NoNewWindow -RedirectStandardOutput stdout.log -RedirectStandardError stderr.log

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\Program Files\New relic\nrjmx\bin\nrjmx.bat"
Start-Process "C:\newrelic\var\db\newrelic-infra\nri-discovery-kubernetes.exe"

Write-Output "zzNew Relic Infrastructure started successfully"

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
}
Loading