Skip to content

Commit

Permalink
Remove final python dep for debian based systems
Browse files Browse the repository at this point in the history
  • Loading branch information
joshrendek committed Sep 24, 2023
1 parent ad46b70 commit f095f7e
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 73 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ ENV DOCKER true
ENV CGO_ENABLED 0
ENV SKIP_UPDATES true
WORKDIR /go/src/bitbucket.org/sysward/sysward-agent
ADD go.mod .
RUN go mod tidy
ADD . .
CMD ["make"]
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ BUILD_NUMBER=${GITHUB_RUN_ID}
all: build

test:
go test -v
go test -v ./...

build: test build_agent

Expand Down
4 changes: 0 additions & 4 deletions agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,7 @@ func TestAgentStartup(t *testing.T) {
config_json, _ := ioutil.ReadFile("config.json")
f.On("FileExists", "/usr/lib/update-notifier/apt-check").Return(true)
f.On("FileExists", "/etc/apt").Return(true)
f.On("FileExists", "/usr/bin/python").Return(true)
f.On("FileExists", "/usr/lib/python2.7/dist-packages/apt/__init__.py").Return(true).Maybe()
f.On("FileExists", "/usr/lib/python3/dist-packages/apt/__init__.py").Return(true).Maybe()
f.On("ReadFile", "config.json").Return(config_json, nil)
r.On("Run", "python", []string{"trex.py"}).Return("", nil)
agent := NewAgent()
runner = r
fileReader = f
Expand Down
62 changes: 54 additions & 8 deletions apt.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package main

import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/sysward/sysward-agent/logging"
"os"
// "strconv"
"strings"
"github.com/sysward/sysward-agent/logging"
)

type DebianPackageManager struct{}
Expand Down Expand Up @@ -86,15 +86,61 @@ func (pm DebianPackageManager) BuildInstalledPackageList() []string {
}

func (pm DebianPackageManager) BuildPackageList() []OsPackage {
out, err := runner.Run("python", "trex.py")
if err != nil {
panic(err)
}
var packages []OsPackage

err = json.Unmarshal([]byte(out), &packages)
out, err := runner.RunBytes("apt-get", "-s", "upgrade")
if err != nil {
panic(err)
fmt.Println("Error:", err)
return nil
}

// Parse the output
lines := bytes.Split(out, []byte("\n"))
for _, line := range lines {
parts := bytes.Fields(line)
if len(parts) < 5 {
continue
}

if !bytes.Contains(line, []byte("Inst")) {
continue
}

// Parse the package information
name := strings.Split(string(parts[1]), "/")[0]

out, err = runner.RunBytes("dpkg", "-s", name)
if err != nil {
fmt.Println("Error:", err)
continue
}
availableVersion := strings.Replace(string(parts[3]), "(", "", -1)
var installedVersion string
var priority string
var section string
dpkgLines := bytes.Split(out, []byte("\n"))
for _, l := range dpkgLines {
if bytes.HasPrefix(l, []byte("Version: ")) {
installedVersion = strings.TrimSpace(string(l[9:]))
}
if bytes.HasPrefix(l, []byte("Priority: ")) {
priority = string(l[10:])
}
if bytes.HasPrefix(l, []byte("Section: ")) {
section = string(l[9:])
}
}

isSecurity := bytes.Contains(parts[4], []byte("Security"))

pkg := OsPackage{Name: name,
Current_version: installedVersion,
Candidate_version: availableVersion,
Priority: priority,
Section: section,
Security: isSecurity,
}
packages = append(packages, pkg)
}

return packages
Expand Down
46 changes: 42 additions & 4 deletions apt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,51 @@ func TestPackagesThatNeedUpdates(t *testing.T) {
Convey("Given pending updates", t, func() {

Convey("There should be a list of packages available for update", func() {
mockValue := `[{"name": "apt", "section": "admin", "priority": "important", "current_version": "1.0.1ubuntu2", "security": true, "candidate_version": "1.0.1ubuntu2.1"}]`
mockValue := `
Inst apport [2.20.11-0ubuntu82.4] (2.20.11-0ubuntu82.5 Ubuntu:22.04/jammy-updates [all])
`
dpkMock := `
Package: apport
Status: install ok installed
Priority: optional
Section: utils
Installed-Size: 812
Maintainer: Ubuntu Developers <[email protected]>
Architecture: all
Version: 2.20.11-0ubuntu82.4
Replaces: core-dump-handler, python-apport (<< 2.2-0ubuntu1)
Provides: core-dump-handler
Depends: python3, python3-apport (>= 2.20.11-0ubuntu82.4), lsb-base (>= 3.0-6), python3-gi, gir1.2-glib-2.0 (>= 1.29.17)
Recommends: apport-symptoms, python3-systemd
Suggests: apport-gtk | apport-kde, policykit-1
Breaks: python-apport (<< 2.2-0ubuntu1)
Conflicts: core-dump-handler
Conffiles:
/etc/apport/blacklist.d/README.blacklist c2ed1eb9a17ec2550747b4960cf4b73c
/etc/apport/blacklist.d/apport 44503501302b80099552bac0204a45c1
/etc/apport/crashdb.conf 4202dae3eccfa5bbb33a0a9acfcd3724
/etc/bash_completion.d/apport_completion dfe766d9328bb5c895038b44185133f9
/etc/cron.daily/apport df5d3bc9ab3a67b58156376318077304
/etc/default/apport 3446c6cac185f44237f59786e006ebe4
/etc/init.d/apport 3d51dc9135014bb49b4a19ff8dab61f1
/etc/logrotate.d/apport fa54dab59ef899b48d5455c976008df4
Description: automatically generate crash reports for debugging
apport automatically collects data from crashed processes and
compiles a problem report in /var/crash/. This utilizes the crashdump
helper hook provided by the Ubuntu kernel.
.
This package also provides a command line frontend for browsing and
handling the crash reports. For desktops, you should consider
installing the GTK+ or Qt user interface (apport-gtk or apport-kde).
Homepage: https://wiki.ubuntu.com/Apport
`
r := new(MockRunner)
r.On("Run", "python", []string{"trex.py"}).Return(mockValue, nil)
r.On("RunBytes", "apt-get", []string{"-s", "upgrade"}).Return(mockValue, nil)
r.On("RunBytes", "dpkg", []string{"-s", "apport"}).Return(dpkMock, nil)
runner = r
osPackages := packageManager.BuildPackageList()
So(osPackages[0].Name, ShouldEqual, "apt")
So(osPackages[0].Security, ShouldEqual, true)
So(osPackages[0].Name, ShouldEqual, "apport")
So(osPackages[0].Security, ShouldEqual, false)
r.Mock.AssertExpectations(t)
})
})
Expand Down
4 changes: 4 additions & 0 deletions job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func TestJobPostback(t *testing.T) {
func TestRunningAllJobs(t *testing.T) {
pm := new(MockPackageManager)
a := new(MockSyswardApi)
f := new(MockReader)

Convey("Given there are jobs", t, func() {

Expand All @@ -113,10 +114,13 @@ func TestRunningAllJobs(t *testing.T) {
}
a.On("JobPostBack", jobs[0]).Return()
a.On("JobPostBack", jobs[1]).Return()
f.On("ReadFile", "/opt/sysward/bin/uid").Return([]byte("uid123"), nil)
f.On("FileExists", "/opt/sysward/bin/uid").Return(true)
pm.On("UpdatePackage", "apt").Return(nil)
pm.On("UpdatePackage", "foo").Return(nil)
packageManager = pm
api = a
fileReader = f
runAllJobs(jobs)
pm.Mock.AssertExpectations(t)
a.Mock.AssertExpectations(t)
Expand Down
44 changes: 0 additions & 44 deletions operating_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,50 +79,6 @@ func checkPreReqs() {
logging.LogMsg(out)
}

if !fileReader.FileExists("/usr/bin/python") {
fmt.Println("python not found, installing")
_, err := runner.Run("apt-get", "update")
out, err := runner.Run("apt-get", "install", "python", "-y")
if err != nil {
logging.LogMsg("error installing python, trying fallbacks: " + err.Error())
}
logging.LogMsg(out)
}

if !fileReader.FileExists("/usr/lib/python2.7/dist-packages/apt/__init__.py") &&
!fileReader.FileExists("/usr/lib/python3/dist-packages/apt/__init__.py") {
fmt.Println("python-apt not found, installing")
_, err := runner.Run("apt-get", "update")
out, err := runner.Run("apt-get", "install", "python-apt", "-y")
if err != nil {
logging.LogMsg(err.Error())
}
logging.LogMsg(out)
}

out, err := runner.Run("python", "trex.py")
if err != nil {
logging.LogMsg("error running python-apt(err): " + err.Error())
logging.LogMsg("error running python-apt(out): " + out)
// Specifically for older debian/ubuntu's
if strings.Contains(out, "ImportError: No module named apt") {
logging.LogMsg("installing python-apt")
_, err := runner.Run("apt-get", "install", "python-apt", "-y")
if err != nil {
logging.LogMsg(err.Error())
}
}
// Specifically for Ubuntu 21+/Debian11+
if strings.Contains(out, "ImportError: No module named apt") ||
strings.Contains(err.Error(), "executable file not found in") {
logging.LogMsg("installing python-is-python3")
_, err := runner.Run("apt-get", "install", "python-is-python3", "-y")
if err != nil {
panic(err)
}
}
}

} else if agent.linux == "centos" {

if !fileReader.FileExists("/usr/bin/needs-restarting") {
Expand Down
16 changes: 6 additions & 10 deletions operating_system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,13 @@ func TestPrereqs(t *testing.T) {
f := new(MockReader)
agent := NewAgent()
agent.linux = "debian"
f.On("FileExists", "/usr/lib/update-notifier/apt-check").Return(true)
f.On("FileExists", "/usr/bin/python").Return(true)
f.On("FileExists", "/usr/lib/python2.7/dist-packages/apt/__init__.py").Return(true)
f.On("FileExists", "/usr/lib/python3/dist-packages/apt/__init__.py").Return(false).Maybe()
fileReader = f
r := new(MockRunner)
f.On("FileExists", "/usr/lib/update-notifier/apt-check").Return(false)
r.On("Run", "apt-get", []string{"update"}).Return("", nil)
r.On("Run", "apt-get", []string{"install", "update-notifier", "-y"}).Return("", nil)
fileReader = f
runner = r
So(func() { checkPreReqs() }, ShouldNotPanic)
// here
f.Mock.AssertExpectations(t)
Expand All @@ -127,14 +129,8 @@ func TestPrereqs(t *testing.T) {
r := new(MockRunner)
f := new(MockReader)
f.On("FileExists", "/usr/lib/update-notifier/apt-check").Return(false)
f.On("FileExists", "/usr/bin/python").Return(false)
f.On("FileExists", "/usr/lib/python2.7/dist-packages/apt/__init__.py").Return(false).Maybe()
f.On("FileExists", "/usr/lib/python3/dist-packages/apt/__init__.py").Return(false).Maybe()
r.On("Run", "apt-get", []string{"update"}).Return("", nil)
r.On("Run", "apt-get", []string{"install", "update-notifier", "-y"}).Return("", nil)
r.On("Run", "apt-get", []string{"install", "python", "-y"}).Return("", nil)
r.On("Run", "apt-get", []string{"install", "python-apt", "-y"}).Return("", nil)
r.On("Run", "python", []string{"trex.py"}).Return("", nil)
fileReader = f
runner = r
// here
Expand Down
10 changes: 8 additions & 2 deletions sysward_runner.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
package main

import (
"github.com/sysward/sysward-agent/logging"
"fmt"
"github.com/sysward/sysward-agent/logging"
"os"
"os/exec"
)

type Runner interface {
Run(string, ...string) (string, error)
RunBytes(string, ...string) ([]byte, error)
}

type SyswardRunner struct{}

func (r SyswardRunner) Run(command string, args ...string) (string, error) {
func (r SyswardRunner) RunBytes(command string, args ...string) ([]byte, error) {
cmd := exec.Command(command, args...)
cmd.Env = append(os.Environ(), "DEBIAN_FRONTEND=noninteractive")
out, err := cmd.CombinedOutput()
if os.Getenv("DEBUG") == "true" {
logging.LogMsg(fmt.Sprintf("Command: %s %#v", command, args))
}
return out, err
}

func (r SyswardRunner) Run(command string, args ...string) (string, error) {
out, err := r.RunBytes(command, args...)
return string(out), err
}
7 changes: 7 additions & 0 deletions test_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ func (r *MockRunner) Run(command string, args ...string) (string, error) {
return _args.String(0), _args.Error(1)
}

func (r *MockRunner) RunBytes(command string, args ...string) ([]byte, error) {
pa := []string{}
pa = append(pa, args...)
_args := r.Mock.Called(command, pa)
return []byte(_args.String(0)), _args.Error(1)
}

/* Mock writer for writing to files */
type MockWriter struct {
mock.Mock
Expand Down

0 comments on commit f095f7e

Please sign in to comment.