From 5d437427d01bbe290662dda39c53d5c5db5b8f01 Mon Sep 17 00:00:00 2001 From: Charlie Getzen Date: Sun, 1 Mar 2026 11:00:26 -0600 Subject: [PATCH 1/4] init --- internal/network/proxy_validator.go | 13 +++++- internal/ssm/config.go | 2 +- internal/ssm/daemon.go | 29 +++++++++---- internal/ssm/daemon_test.go | 65 +++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 internal/ssm/daemon_test.go diff --git a/internal/network/proxy_validator.go b/internal/network/proxy_validator.go index e3a19865c..10b799cb2 100644 --- a/internal/network/proxy_validator.go +++ b/internal/network/proxy_validator.go @@ -179,7 +179,11 @@ func validateSSMProxyConfig(osName string) error { var ssmServicePath string switch osName { case system.UbuntuOsName: - ssmServicePath = "/etc/systemd/system/snap.amazon-ssm-agent.amazon-ssm-agent.service.d/http-proxy.conf" + if isSnapSSMInstall() { + ssmServicePath = "/etc/systemd/system/snap.amazon-ssm-agent.amazon-ssm-agent.service.d/http-proxy.conf" + } else { + ssmServicePath = "/etc/systemd/system/amazon-ssm-agent.service.d/http-proxy.conf" + } case system.RhelOsName, system.AmazonOsName: ssmServicePath = "/etc/systemd/system/amazon-ssm-agent.service.d/http-proxy.conf" default: @@ -189,6 +193,13 @@ func validateSSMProxyConfig(osName string) error { return validateSystemdServiceProxyConfig("SSM", ssmServicePath) } +const snapSSMAgentBinaryPath = "/snap/amazon-ssm-agent/current/amazon-ssm-agent" + +func isSnapSSMInstall() bool { + _, err := os.Stat(snapSSMAgentBinaryPath) + return !os.IsNotExist(err) +} + // validateAptProxyConfig validates the apt proxy configuration func validateAptProxyConfig(httpProxy, httpsProxy string) error { aptConfPath := "/etc/apt/apt.conf.d/proxy.conf" diff --git a/internal/ssm/config.go b/internal/ssm/config.go index 0113cadc2..9610cbdda 100644 --- a/internal/ssm/config.go +++ b/internal/ssm/config.go @@ -70,7 +70,7 @@ func (s *ssm) registerMachine(ctx context.Context, cfg *api.NodeConfig) error { var possibleAgentPaths = []string{ "/usr/bin/amazon-ssm-agent", - "/snap/amazon-ssm-agent/current/amazon-ssm-agent", + snapAgentBinaryPath, } func agentBinaryPath() (string, error) { diff --git a/internal/ssm/daemon.go b/internal/ssm/daemon.go index 78487e04b..fb26bd2f9 100644 --- a/internal/ssm/daemon.go +++ b/internal/ssm/daemon.go @@ -27,6 +27,10 @@ const ( awsCredentialsFilePath = defaultAWSConfigPath + "/credentials" eksHybridPath = "/eks-hybrid" symlinkedAWSConfigPath = eksHybridPath + "/.aws" + + snapAgentBinaryPath = "/snap/amazon-ssm-agent/current/amazon-ssm-agent" + snapSsmDaemonName = "snap.amazon-ssm-agent.amazon-ssm-agent" + defaultSsmDaemonName = "amazon-ssm-agent" ) type ssm struct { @@ -119,13 +123,22 @@ func (s *ssm) Name() string { } func setDaemonName() { - osToDaemonName := map[string]string{ - system.UbuntuOsName: "snap.amazon-ssm-agent.amazon-ssm-agent", - system.RhelOsName: "amazon-ssm-agent", - system.AmazonOsName: "amazon-ssm-agent", - } - osName := system.GetOsName() - if daemonName, ok := osToDaemonName[osName]; ok { - SsmDaemonName = daemonName + SsmDaemonName = resolveDaemonName(system.GetOsName(), fileExists) +} + +// resolveDaemonName determines the correct SSM daemon name based on the OS and +// how the agent was installed. On Ubuntu, SSM can be installed via snap or deb; +// this function checks for the snap binary to distinguish between the two. +func resolveDaemonName(osName string, exists func(string) bool) string { + switch osName { + case system.UbuntuOsName: + if exists(snapAgentBinaryPath) { + return snapSsmDaemonName + } + return defaultSsmDaemonName + case system.RhelOsName, system.AmazonOsName: + return defaultSsmDaemonName + default: + return defaultSsmDaemonName } } diff --git a/internal/ssm/daemon_test.go b/internal/ssm/daemon_test.go new file mode 100644 index 000000000..a69ea5c91 --- /dev/null +++ b/internal/ssm/daemon_test.go @@ -0,0 +1,65 @@ +package ssm + +import ( + "testing" + + "github.com/aws/eks-hybrid/internal/system" +) + +func TestResolveDaemonName(t *testing.T) { + tests := []struct { + name string + osName string + snapExists bool + expectedName string + }{ + { + name: "ubuntu with snap install", + osName: system.UbuntuOsName, + snapExists: true, + expectedName: snapSsmDaemonName, + }, + { + name: "ubuntu with deb install", + osName: system.UbuntuOsName, + snapExists: false, + expectedName: defaultSsmDaemonName, + }, + { + name: "rhel", + osName: system.RhelOsName, + snapExists: false, + expectedName: defaultSsmDaemonName, + }, + { + name: "amazon linux", + osName: system.AmazonOsName, + snapExists: false, + expectedName: defaultSsmDaemonName, + }, + { + name: "unknown os", + osName: "unknown", + snapExists: false, + expectedName: defaultSsmDaemonName, + }, + { + name: "empty os name", + osName: "", + snapExists: false, + expectedName: defaultSsmDaemonName, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + exists := func(path string) bool { + return tt.snapExists && path == snapAgentBinaryPath + } + got := resolveDaemonName(tt.osName, exists) + if got != tt.expectedName { + t.Errorf("resolveDaemonName(%q) = %q, want %q", tt.osName, got, tt.expectedName) + } + }) + } +} From fefaf91033adca99c79f8c90462d9b15b04f78fc Mon Sep 17 00:00:00 2001 From: Charlie Getzen Date: Fri, 13 Mar 2026 10:52:27 -0500 Subject: [PATCH 2/4] fix --- internal/packagemanager/packagemanager.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/internal/packagemanager/packagemanager.go b/internal/packagemanager/packagemanager.go index 69fae6c38..b282a19a0 100644 --- a/internal/packagemanager/packagemanager.go +++ b/internal/packagemanager/packagemanager.go @@ -245,11 +245,11 @@ func (pm *DistroPackageManager) GetIptables() artifact.Package { ) } -// GetSSMPackage satisfies the getssmpackage source interface +// GetSSMPackage satisfies the getssmpackage source interface. +// On apt-based systems (Ubuntu), SSM may be installed via snap or via deb. +// We check for the snap binary to determine which package manager to use. func (pm *DistroPackageManager) GetSSMPackage() artifact.Package { - // SSM is installed using snap package manager. If apt package manager - // is detected, use snap to install/uninstall SSM. - if pm.manager == aptPackageManager { + if pm.manager == aptPackageManager && isSnapSSMInstall() { return artifact.NewPackageSource( artifact.NewCmd(snapPackageManager, snapInstallVerb, ssmPkgName), artifact.NewCmd(snapPackageManager, snapRemoveVerb, ssmPkgName), @@ -263,6 +263,13 @@ func (pm *DistroPackageManager) GetSSMPackage() artifact.Package { ) } +const snapSSMAgentBinaryPath = "/snap/amazon-ssm-agent/current/amazon-ssm-agent" + +func isSnapSSMInstall() bool { + _, err := os.Stat(snapSSMAgentBinaryPath) + return !os.IsNotExist(err) +} + func (pm *DistroPackageManager) caCertsPackage() artifact.Package { return artifact.NewPackageSource( artifact.NewCmd(pm.manager, pm.installVerb, caCertsPkgName, "-y"), From 27fbdcaec68ed68701a6719ad65229d477bde25b Mon Sep 17 00:00:00 2001 From: Charlie Getzen Date: Fri, 13 Mar 2026 11:21:24 -0500 Subject: [PATCH 3/4] push --- .github/workflows/build-and-test.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 77a62f638..bc66712fb 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -24,6 +24,23 @@ jobs: cache: true - name: build application run: make build-cross-platform + - name: package nodeadm binaries + run: | + mkdir -p dist + tar -C _bin/amd64 -czf dist/nodeadm-linux-amd64.tar.gz nodeadm + tar -C _bin/arm64 -czf dist/nodeadm-linux-arm64.tar.gz nodeadm + sha256sum dist/nodeadm-linux-amd64.tar.gz > dist/nodeadm-linux-amd64.tar.gz.sha256 + sha256sum dist/nodeadm-linux-arm64.tar.gz > dist/nodeadm-linux-arm64.tar.gz.sha256 + - name: upload nodeadm artifacts + uses: actions/upload-artifact@v4 + with: + name: nodeadm-linux-binaries-${{ github.sha }} + path: | + dist/nodeadm-linux-amd64.tar.gz + dist/nodeadm-linux-amd64.tar.gz.sha256 + dist/nodeadm-linux-arm64.tar.gz + dist/nodeadm-linux-arm64.tar.gz.sha256 + retention-days: 14 test: name: unit-test runs-on: ubuntu-latest From 0dfbb63c3dc72a0f6a065f1836b55e9dcd8d51d8 Mon Sep 17 00:00:00 2001 From: Charlie Getzen Date: Fri, 13 Mar 2026 11:23:13 -0500 Subject: [PATCH 4/4] go format --- internal/ssm/daemon.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/ssm/daemon.go b/internal/ssm/daemon.go index fb26bd2f9..214aa2dd0 100644 --- a/internal/ssm/daemon.go +++ b/internal/ssm/daemon.go @@ -28,8 +28,8 @@ const ( eksHybridPath = "/eks-hybrid" symlinkedAWSConfigPath = eksHybridPath + "/.aws" - snapAgentBinaryPath = "/snap/amazon-ssm-agent/current/amazon-ssm-agent" - snapSsmDaemonName = "snap.amazon-ssm-agent.amazon-ssm-agent" + snapAgentBinaryPath = "/snap/amazon-ssm-agent/current/amazon-ssm-agent" + snapSsmDaemonName = "snap.amazon-ssm-agent.amazon-ssm-agent" defaultSsmDaemonName = "amazon-ssm-agent" )