Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ lint:

.PHONY: proto
proto:
test -z $(shell protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative internal/api/api.proto >/dev/null 2>&1 || echo 1) || (echo "[WARN] Fix proto generation issues" && exit 1)
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative internal/api/api.proto

.PHONY: dist
dist:
Expand Down
4 changes: 4 additions & 0 deletions cmd/agent/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func runDescribeCmd(cmd *cobra.Command, args []string) {
t := tablewriter.NewWriter(os.Stdout)
t.Header([]string{"Property", "Value"})
_ = t.Append([]string{"Hostname", desc.Hostname})
_ = t.Append([]string{"Node", desc.Node})
if (len(desc.Labels)) > 0 {
_ = t.Append([]string{"Labels", strings.Join(desc.Labels, ", ")})
}
Expand All @@ -65,6 +66,9 @@ func runDescribeCmd(cmd *cobra.Command, args []string) {
if (len(desc.Logs.Files)) > 0 {
_ = t.Append([]string{"Files", strings.Join(desc.Logs.Files, "\n")})
}
if (len(desc.Logs.Events)) > 0 {
_ = t.Append([]string{"Events", strings.Join(desc.Logs.Events, "\n")})
}
_ = t.Append([]string{"Metrics", fmt.Sprintf("%v", desc.Metrics.Enable)})
if (len(desc.Metrics.Targets)) > 0 {
_ = t.Append([]string{"Metrics targets", strings.Join(desc.Metrics.Targets, "\n")})
Expand Down
17 changes: 17 additions & 0 deletions cmd/agent/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ func init() {

registerCmd.Flags().String("agent.config", "finch-agent.cfg", "Path to the configuration file")
registerCmd.Flags().String("agent.file", "", "Path to a file containing agent data")

registerCmd.Flags().StringSlice("agent.logs.events", nil, "Collect windows log events")
_ = viper.BindPFlag("logs.events", registerCmd.Flags().Lookup("agent.logs.events"))

registerCmd.Flags().String("agent.node", "unix", "Node type of the agent (unix, windows)")
_ = viper.BindPFlag("agent.node", registerCmd.Flags().Lookup("agent.node"))

_ = registerCmd.RegisterFlagCompletionFunc("agent.node", completion.CompleteNodeName)
}

func runRegisterPreCmd(cmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -104,10 +112,18 @@ func parseFlags(formatType target.Format) *agent.RegisterData {
}
}

logEvents := viper.GetStringSlice("logs.events")
if len(logEvents) != 0 {
for _, event := range logEvents {
logSources = append(logSources, "event://"+event)
}
}

if len(logSources) == 0 {
errors.CheckErr("at least one log source must be enabled", formatType)
}

node := viper.GetString("agent.node")
labels := viper.GetStringSlice("labels")
metrics := viper.GetBool("metrics.enable")
metricsTargets := viper.GetStringSlice("metrics.targets")
Expand All @@ -124,6 +140,7 @@ func parseFlags(formatType target.Format) *agent.RegisterData {
MetricsTargets: metricsTargets,
Profiles: profiles,
Labels: labels,
Node: node,
}

return data
Expand Down
8 changes: 8 additions & 0 deletions cmd/completion/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,11 @@ func CompleteStackName(cmd *cobra.Command, args []string, toComplete string) ([]

return stacks, cobra.ShellCompDirectiveNoFileComp
}

func CompleteNodeName(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}

return []string{"unix", "windows"}, cobra.ShellCompDirectiveNoFileComp
}
36 changes: 36 additions & 0 deletions contrib/install-latest-alloy.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
$ErrorActionPreference = "Stop"
$installDir = "C:\Program Files\Alloy"
$githubRepo = "grafana/alloy"

Write-Host "`nFetching latest Alloy release info from GitHub..."
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/$githubRepo/releases/latest" `
-Headers @{ "User-Agent" = "PowerShell" }

$asset = $release.assets | Where-Object { $_.name -eq "alloy-windows-amd64.exe.zip" } | Select-Object -First 1

if (-not $asset) {
Write-Error "Could not find alloy-windows-amd64.exe.zip in the latest release!"
exit 1
}

$tempZip = "$env:TEMP\alloy-latest.zip"
Write-Host "Downloading: $($asset.browser_download_url)"
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $tempZip

Write-Host "Extracting to $installDir ..."
if (!(Test-Path $installDir)) {
New-Item -ItemType Directory -Path $installDir | Out-Null
}
Expand-Archive -Path $tempZip -DestinationPath $installDir -Force

$sysPath = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
if ($sysPath -notmatch [regex]::Escape($installDir)) {
[System.Environment]::SetEnvironmentVariable("Path", "$sysPath;$installDir", "Machine")
Write-Host "Added $installDir to system PATH."
} else {
Write-Host "$installDir is already in PATH."
}

Write-Host "`nAlloy binary is now installed at $installDir."
Write-Host "You can run it with: alloy.exe"
Write-Host "To start as service or autostart, please configure according to your environment."
26 changes: 26 additions & 0 deletions internal/agent/assets/com.github.tschaefer.finch.agent.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.github.tschaefer.finch.agent</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/alloy</string>
<string>run</string>
<string>--storage.path=/var/lib/alloy/data</string>
<string>--disable-reporting=true</string>
<string>/etc/alloy/alloy.config</string>
</array>
<key>WorkingDirectory</key>
<string>/var/lib/alloy</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/var/log/alloy.log</string>
<key>StandardErrorPath</key>
<string>/var/log/alloy.log</string>
</dict>
</plist>
62 changes: 59 additions & 3 deletions internal/agent/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,32 @@ func (a *Agent) __deployCopyRcServiceFile() error {
return nil
}

func (a *Agent) __deployCopyLaunchdServiceFile() error {
dest := "/Library/LaunchDaemons/com.github.tschaefer.finch.agent.plist"

content, err := fs.ReadFile(Assets, "com.github.tschaefer.finch.agent.plist")
if err != nil {
return &DeployAgentError{Message: err.Error(), Reason: ""}
}

f, err := os.CreateTemp("", "com.github.tschaefer.finch.agent.plist")
if err != nil {
return &DeployAgentError{Message: err.Error(), Reason: ""}
}
defer func() {
_ = os.Remove(f.Name())
}()
if _, err := f.Write(content); err != nil {
return &DeployAgentError{Message: err.Error(), Reason: ""}
}

if err := a.target.Copy(f.Name(), dest, "444", "0:0"); err != nil {
return &DeployAgentError{Message: err.Error(), Reason: ""}
}

return nil
}

func (a *Agent) __deployDownloadRelease(release string, version string, tmpdir string) (string, error) {
var url string
if version != "latest" {
Expand Down Expand Up @@ -210,8 +236,17 @@ func (a *Agent) __deployUnzipRelease(release string, file string) (string, error
return binary.Name(), nil
}

func (a *Agent) __deployInstallBinary(binary string) error {
err := a.target.Copy(binary, "/usr/bin/alloy", "755", "0:0")
func (a *Agent) __deployInstallBinary(binary string, machine *MachineInfo) error {
path := "/usr/bin/alloy"
if machine.Kernel == "darwin" {
path = "/usr/local/bin/alloy"
out, err := a.target.Run("sudo mkdir -p " + filepath.Dir(path))
if err != nil {
return &DeployAgentError{Message: err.Error(), Reason: string(out)}
}
}

err := a.target.Copy(binary, path, "755", "0:0")
if err != nil {
return &DeployAgentError{Message: err.Error(), Reason: ""}
}
Expand Down Expand Up @@ -241,6 +276,20 @@ func (a *Agent) __deployEnableRcService() error {
return nil
}

func (a *Agent) __deployEnableLaunchdService() error {
out, err := a.target.Run("sudo launchctl bootstrap system /Library/LaunchDaemons/com.github.tschaefer.finch.agent.plist")
if err != nil {
return &DeployAgentError{Message: err.Error(), Reason: string(out)}
}

out, err = a.target.Run("sudo launchctl kickstart -k system/com.github.tschaefer.finch.agent")
if err != nil {
return &DeployAgentError{Message: err.Error(), Reason: string(out)}
}

return nil
}

func (a *Agent) __helperPrintProgress(message string) {
username := "unknown"
user, err := user.Current()
Expand Down Expand Up @@ -279,7 +328,7 @@ func (a *Agent) deployAgent(machine *MachineInfo, alloyVersion string) error {
return err
}

if err := a.__deployInstallBinary(binary); err != nil {
if err := a.__deployInstallBinary(binary, machine); err != nil {
return err
}

Expand All @@ -298,6 +347,13 @@ func (a *Agent) deployAgent(machine *MachineInfo, alloyVersion string) error {
if err := a.__deployEnableRcService(); err != nil {
return err
}
case "darwin":
if err := a.__deployCopyLaunchdServiceFile(); err != nil {
return err
}
if err := a.__deployEnableLaunchdService(); err != nil {
return err
}
default:
// no-op
}
Expand Down
15 changes: 10 additions & 5 deletions internal/agent/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type DescribeLogsDocker struct {
}

type DescribeLogs struct {
Events []string `json:"events"`
Files []string `json:"files"`
Journal DescribeLogsJournal `json:"journal"`
Docker DescribeLogsDocker `json:"docker"`
Expand All @@ -39,6 +40,7 @@ type DescribeProfiles struct {
type DescribeData struct {
ResourceID string `json:"rid"`
Hostname string `json:"hostname"`
Node string `json:"node"`
Labels []string `json:"labels"`
Logs DescribeLogs `json:"logs"`
Metrics DescribeMetrics `json:"metrics"`
Expand Down Expand Up @@ -67,6 +69,7 @@ func (a *Agent) describeAgent(service, rid string) (*DescribeData, error) {
journal := false
docker := false
files := []string{}
events := []string{}
for _, src := range data.LogSources {
url, err := url.Parse(src)
if err != nil {
Expand All @@ -76,13 +79,13 @@ func (a *Agent) describeAgent(service, rid string) (*DescribeData, error) {
switch url.Scheme {
case "journal":
journal = true
continue
case "docker":
docker = true
continue
case "file":
files = append(files, url.Path)
case "event":
events = append(events, url.Host)
}

files = append(files, url.Path)
}

labels := data.Labels
Expand All @@ -98,9 +101,11 @@ func (a *Agent) describeAgent(service, rid string) (*DescribeData, error) {
return &DescribeData{
ResourceID: data.ResourceId,
Hostname: data.Hostname,
Node: data.Node,
Labels: labels,
Logs: DescribeLogs{
Files: files,
Events: events,
Files: files,
Journal: DescribeLogsJournal{
Enable: journal,
},
Expand Down
3 changes: 1 addition & 2 deletions internal/agent/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,10 @@ func (a *Agent) machineInfo() (*MachineInfo, error) {
return nil, fmt.Errorf("unsupported target init system: %w", err)
}
case "darwin":
_, err = a.__machineGetDarwinArch(machine)
arch, err = a.__machineGetDarwinArch(machine)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("yet unsupported target kernel: %s", kernel)
case "freebsd":
arch, err = a.__machineGetFreebsdArch(machine)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions internal/agent/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type RegisterData struct {
MetricsTargets []string `json:"metrics_targets"`
Profiles bool `json:"profiles"`
Labels []string `json:"labels"`
Node string `json:"node"`
}

func (a *Agent) registerAgent(service string, data *RegisterData) ([]byte, error) {
Expand All @@ -40,6 +41,7 @@ func (a *Agent) registerAgent(service string, data *RegisterData) ([]byte, error
MetricsTargets: data.MetricsTargets,
Profiles: data.Profiles,
Labels: data.Labels,
Node: data.Node,
})
if err != nil {
return nil, &RegisterAgentError{Message: err.Error(), Reason: ""}
Expand Down
35 changes: 28 additions & 7 deletions internal/agent/teardown.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,35 @@ func (a *Agent) __teardownRcService() error {
return nil
}

func (a *Agent) __teardownLaunchdService() error {
out, err := a.target.Run("sudo launchctl bootout system/com.github.tschaefer.finch.agent || true")
if err != nil {
return &TeardownAgentError{Message: err.Error(), Reason: string(out)}
}

out, err = a.target.Run("sudo rm -f /Library/LaunchDaemons/com.github.tschaefer.finch.agent.plist")
if err != nil {
return &TeardownAgentError{Message: err.Error(), Reason: string(out)}
}

return nil
}

func (a *Agent) teardownAgent(machine *MachineInfo) error {
var err error
switch machine.Kernel {
case "linux":
if err := a.__teardownSystemdService(); err != nil {
return err
}
err = a.__teardownSystemdService()
case "freebsd":
if err := a.__teardownRcService(); err != nil {
return err
}
err = a.__teardownRcService()
case "darwin":
err = a.__teardownLaunchdService()
default:
// no-op
}
if err != nil {
return err
}

out, err := a.target.Run("sudo rm -rf /etc/alloy")
if err != nil {
Expand All @@ -66,7 +82,12 @@ func (a *Agent) teardownAgent(machine *MachineInfo) error {
return &TeardownAgentError{Message: err.Error(), Reason: string(out)}
}

out, err = a.target.Run("sudo rm -f /usr/bin/alloy")
path := "/usr/bin/alloy"
if machine.Kernel == "darwin" {
path = "/usr/local/bin/alloy"
}

out, err = a.target.Run("sudo rm -f " + path)
if err != nil {
return &TeardownAgentError{Message: err.Error(), Reason: string(out)}
}
Expand Down
Loading