Repository: osbuild/osbuild-composer
Pull request #2811 (2022-07-08 12:08:20)

Introduce logging adapter for jobqueue
Thanks for extracting jobqueue into pkg/. Now, in order to use it in our project, we have two changes to make:

* We rely on database/sql connection pool instead of pgx.
* We do not use logrus.

This patch aims to solve the latter by creating a very simple facade via interface called `SimpleLogger` (naming things is hard bring your own suggestions). It seems the jobqueue only uses logging messages at info level and then error level, so the interface only supports these to keep things simple. It makes sense, as a user of any library you typically want to either enable or disable logging, verbosity mapping has always been problematic thing to solve.

The patch introduces a logrus implementation and a noop implementation. It will require a change in all callers of the New function, I tried my best to find all uses, but since I do not have a full development setup yet, I could not test this properly.
 
This pull request includes:

- [ ] adequate testing for the new functionality or fixed issue
- [x] adequate documentation informing people about the change (not relevant I guess)

I am going to make a draft first to gather feedback. I would appreciate any help in regard to how to test this change.

lzap: Rebased, split the IDEA git ignore hunk into a separate commit.
ondrejbudai: Hi @lzap, do you have any plans to get this finished? I'm currently in the process of cleaning up stale PRs. :) Thanks!
lzap: Apologies, I rebased.

I feel like I should remain the old behavior when job queue is created via `New` function, that is logging into the standard logrus logger by default.

But I created a new function `NewWithConfig` and introduced a new `Config` type which allows overriding this behavior. The no operation logger is currently unused, but I think it's a good idea to have it in the codebase - it has literally zero code so there can't be bugs (I think) :-)

Should be building now, fixed some linter complaints.
lzap: Rebased! Thanks.

Patch:
diff --git a/.gitignore b/.gitignore
index a72a0ca51..2d313d277 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ __pycache__
 
 .vscode
 .DS_Store
+/.idea
 
 /containers/config/
 /bin
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 079f1874b..4fdefe3a8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -445,7 +445,9 @@ Rebase OSTree UEFI:
       - aws/rhel-8.6-ga-x86_64
       - aws/rhel-9.0-ga-x86_64
       - aws/rhel-8.7-nightly-x86_64
+      - aws/rhel-8.7-nightly-aarch64
       - aws/rhel-9.1-nightly-x86_64
+      - aws/rhel-9.1-nightly-aarch64
       - aws/centos-stream-9-x86_64
     INTERNAL_NETWORK: ["true"]
 
@@ -514,11 +516,13 @@ aws.sh:
   extends: .integration
   variables:
     SCRIPT: aws.sh
-    
+
 azure.sh:
   extends: .integration
   variables:
     SCRIPT: azure.sh
+  rules:
+    - if: '$RUNNER =~ /[\S]+x86_64[\S]+/'
 
 # The required GCE image type is not supported on Fedora
 gcp.sh:
@@ -532,9 +536,9 @@ gcp.sh:
 
 vmware.sh:
   extends: .integration
-  rules: 
+  rules:
     # WHITELIST
-    - if: $RUNNER =~ "/^.*(rhel).*$/" && $CI_PIPELINE_SOURCE != "schedule"
+    - if: $RUNNER =~ "/^.*(rhel).*$/" && $RUNNER =~ "/^.*(x86_64).*$/" && $CI_PIPELINE_SOURCE != "schedule"
     - !reference [.nightly_rules, rules]
   variables:
     SCRIPT: vmware.sh
diff --git a/Schutzfile b/Schutzfile
index 581061e34..4d99379fa 100644
--- a/Schutzfile
+++ b/Schutzfile
@@ -46,14 +46,14 @@
           {
             "title": "updates",
             "name": "updates",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f35/f35-x86_64-updates-released-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f35/f35-x86_64-updates-released-20220906"
           }
         ],
         "aarch64": [
           {
             "title": "updates",
             "name": "updates",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f35/f35-aarch64-updates-released-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f35/f35-aarch64-updates-released-20220906"
           }
         ]
       },
@@ -63,14 +63,14 @@
           {
             "title": "updates-modular",
             "name": "updates-modular",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f35/f35-x86_64-updates-released-modular-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f35/f35-x86_64-updates-released-modular-20220906"
           }
         ],
         "aarch64": [
           {
             "title": "updates-modular",
             "name": "updates-modular",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f35/f35-aarch64-updates-released-modular-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f35/f35-aarch64-updates-released-modular-20220906"
           }
         ]
       }
@@ -123,14 +123,14 @@
           {
             "title": "updates",
             "name": "updates",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f36/f36-x86_64-updates-released-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f36/f36-x86_64-updates-released-20220906"
           }
         ],
         "aarch64": [
           {
             "title": "updates",
             "name": "updates",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f36/f36-aarch64-updates-released-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f36/f36-aarch64-updates-released-20220906"
           }
         ]
       },
@@ -140,14 +140,14 @@
           {
             "title": "updates-modular",
             "name": "updates-modular",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f36/f36-x86_64-updates-released-modular-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f36/f36-x86_64-updates-released-modular-20220906"
           }
         ],
         "aarch64": [
           {
             "title": "updates-modular",
             "name": "updates-modular",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f36/f36-aarch64-updates-released-modular-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/f36/f36-aarch64-updates-released-modular-20220906"
           }
         ]
       }
@@ -180,34 +180,34 @@
           {
             "title": "RHEL-8-RPMREPO-NIGHTLY-BaseOS",
             "name": "baseos",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.7-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.7-20220906"
           },
           {
             "title": "RHEL-8-RPMREPO-NIGHTLY-AppStream",
             "name": "appstream",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.7-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.7-20220906"
           },
           {
             "title": "RHEL-8-RPMREPO-NIGHTLY-CRB",
             "name": "crb",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-crb-n8.7-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-crb-n8.7-20220906"
           }
         ],
         "aarch64": [
           {
             "title": "RHEL-8-RPMREPO-NIGHTLY-BaseOS",
             "name": "baseos",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-aarch64-baseos-n8.7-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-aarch64-baseos-n8.7-20220906"
           },
           {
             "title": "RHEL-8-RPMREPO-NIGHTLY-AppStream",
             "name": "appstream",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-aarch64-appstream-n8.7-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-aarch64-appstream-n8.7-20220906"
           },
           {
             "title": "RHEL-8-RPMREPO-NIGHTLY-CRB",
             "name": "crb",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-aarch64-crb-n8.7-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-aarch64-crb-n8.7-20220906"
           }
         ]
       }
@@ -233,34 +233,34 @@
           {
             "title": "RHEL-9-RPMREPO-NIGHTLY-BaseOS",
             "name": "baseos",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-x86_64-baseos-n9.1-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-x86_64-baseos-n9.1-20220906"
           },
           {
             "title": "RHEL-9-RPMREPO-NIGHTLY-AppStream",
             "name": "appstream",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-x86_64-appstream-n9.1-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-x86_64-appstream-n9.1-20220906"
           },
           {
             "title": "RHEL-9-RPMREPO-NIGHTLY-CRB",
             "name": "crb",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-x86_64-crb-n9.1-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-x86_64-crb-n9.1-20220906"
           }
         ],
         "aarch64": [
           {
             "title": "RHEL-9-RPMREPO-NIGHTLY-BaseOS",
             "name": "baseos",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-aarch64-baseos-n9.1-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-aarch64-baseos-n9.1-20220906"
           },
           {
             "title": "RHEL-9-RPMREPO-NIGHTLY-AppStream",
             "name": "appstream",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-aarch64-appstream-n9.1-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-aarch64-appstream-n9.1-20220906"
           },
           {
             "title": "RHEL-9-RPMREPO-NIGHTLY-CRB",
             "name": "crb",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-aarch64-crb-n9.1-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el9/el9-aarch64-crb-n9.1-20220906"
           }
         ]
       }
@@ -339,14 +339,14 @@
           {
             "title": "baseos",
             "name": "baseos",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-x86_64-baseos-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-x86_64-baseos-20220906"
           }
         ],
         "aarch64": [
           {
             "title": "baseos",
             "name": "baseos",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-aarch64-baseos-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-aarch64-baseos-20220906"
           }
         ]
       },
@@ -356,14 +356,14 @@
           {
             "title": "appstream",
             "name": "appstream",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-x86_64-appstream-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-x86_64-appstream-20220906"
           }
         ],
         "aarch64": [
           {
             "title": "appstream",
             "name": "appstream",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-aarch64-appstream-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-aarch64-appstream-20220906"
           }
         ]
       },
@@ -373,14 +373,14 @@
           {
             "title": "powertools",
             "name": "powertools",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-x86_64-powertools-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-x86_64-powertools-20220906"
           }
         ],
         "aarch64": [
           {
             "title": "powertools",
             "name": "powertoosl",
-            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-aarch64-powertools-20220715"
+            "baseurl": "https://rpmrepo.osbuild.org/v2/mirror/public/el8/cs8-aarch64-powertools-20220906"
           }
         ]
       }
diff --git a/internal/common/slogger/logrus.go b/internal/common/slogger/logrus.go
new file mode 100644
index 000000000..dd99d8abb
--- /dev/null
+++ b/internal/common/slogger/logrus.go
@@ -0,0 +1,38 @@
+package slogger
+
+import (
+	"github.com/osbuild/osbuild-composer/pkg/jobqueue"
+	"github.com/sirupsen/logrus"
+)
+
+type simpleLogrus struct {
+	logger *logrus.Logger
+}
+
+func NewLogrusLogger(logger *logrus.Logger) jobqueue.SimpleLogger {
+	return &simpleLogrus{logger: logger}
+}
+
+func (s *simpleLogrus) log(level logrus.Level, err error, msg string, args ...string) {
+	if len(args)%2 != 0 {
+		panic("log arguments must be even (key value pairs)")
+	}
+	var fields = make(logrus.Fields, len(args)/2+1)
+	for i := 0; i < len(args); i += 2 {
+		k := args[i]
+		v := args[i+1]
+		fields[k] = v
+	}
+	if err != nil {
+		fields["error"] = err.Error()
+	}
+	s.logger.WithFields(fields).Log(level, msg)
+}
+
+func (s *simpleLogrus) Info(msg string, args ...string) {
+	s.log(logrus.InfoLevel, nil, msg, args...)
+}
+
+func (s *simpleLogrus) Error(err error, msg string, args ...string) {
+	s.log(logrus.ErrorLevel, err, msg, args...)
+}
diff --git a/internal/common/slogger/noop.go b/internal/common/slogger/noop.go
new file mode 100644
index 000000000..8782315b8
--- /dev/null
+++ b/internal/common/slogger/noop.go
@@ -0,0 +1,18 @@
+package slogger
+
+import (
+	"github.com/osbuild/osbuild-composer/pkg/jobqueue"
+)
+
+type noopLogger struct {
+}
+
+func NewNoopLogger() jobqueue.SimpleLogger {
+	return &noopLogger{}
+}
+
+func (s *noopLogger) Info(_ string, _ ...string) {
+}
+
+func (s *noopLogger) Error(_ error, _ string, _ ...string) {
+}
diff --git a/pkg/jobqueue/dbjobqueue/dbjobqueue.go b/pkg/jobqueue/dbjobqueue/dbjobqueue.go
index 02dfc5c49..970c41a4c 100644
--- a/pkg/jobqueue/dbjobqueue/dbjobqueue.go
+++ b/pkg/jobqueue/dbjobqueue/dbjobqueue.go
@@ -18,10 +18,9 @@ import (
 	"github.com/jackc/pgtype"
 	"github.com/jackc/pgx/v4"
 	"github.com/jackc/pgx/v4/pgxpool"
-
+	"github.com/osbuild/osbuild-composer/internal/common/slogger"
 	"github.com/osbuild/osbuild-composer/pkg/jobqueue"
-
-	logrus "github.com/sirupsen/logrus"
+	"github.com/sirupsen/logrus"
 )
 
 const (
@@ -106,6 +105,7 @@ const (
 )
 
 type DBJobQueue struct {
+	logger       jobqueue.SimpleLogger
 	pool         *pgxpool.Pool
 	dequeuers    *dequeuers
 	stopListener func()
@@ -153,8 +153,24 @@ func (d *dequeuers) notifyAll() {
 	}
 }
 
-// Create a new DBJobQueue object for `url`.
+// Config allows more detailed customization of queue behavior
+type Config struct {
+	// Logger is used for all logging of the queue, when not provided, the stanard
+	// global logger (logrus) is used.
+	Logger jobqueue.SimpleLogger
+}
+
+// New creates a new DBJobQueue object for `url` with default configuration.
 func New(url string) (*DBJobQueue, error) {
+	stdLogger := slogger.NewLogrusLogger(logrus.StandardLogger())
+	config := Config{
+		Logger: stdLogger,
+	}
+	return NewWithConfig(url, config)
+}
+
+// NewWithLogger creates a new DBJobQueue object for `url` with specific configuration.
+func NewWithConfig(url string, config Config) (*DBJobQueue, error) {
 	pool, err := pgxpool.Connect(context.Background(), url)
 	if err != nil {
 		return nil, fmt.Errorf("error establishing connection: %v", err)
@@ -162,6 +178,7 @@ func New(url string) (*DBJobQueue, error) {
 
 	listenContext, cancel := context.WithCancel(context.Background())
 	q := &DBJobQueue{
+		logger:       config.Logger,
 		pool:         pool,
 		dequeuers:    newDequeuers(),
 		stopListener: cancel,
@@ -185,7 +202,7 @@ func (q *DBJobQueue) listen(ctx context.Context, ready chan<- struct{}) {
 		// use the empty context as the listening context is already cancelled at this point
 		_, err := conn.Exec(context.Background(), sqlUnlisten)
 		if err != nil && !errors.Is(err, context.DeadlineExceeded) {
-			logrus.Error("Error unlistening for jobs in dequeue: ", err)
+			q.logger.Error(err, "Error unlistening for jobs in dequeue")
 		}
 		conn.Release()
 	}()
@@ -202,13 +219,13 @@ func (q *DBJobQueue) listen(ctx context.Context, ready chan<- struct{}) {
 		if err != nil {
 			// shutdown the listener if the context is canceled
 			if errors.Is(err, context.Canceled) {
-				logrus.Info("Shutting down the listener")
+				q.logger.Info("Shutting down the listener")
 				return
 			}
 
 			// otherwise, just log the error and continue, there might just
 			// be a temporary networking issue
-			logrus.Debugf("error waiting for notification on jobs channel: %v", err)
+			q.logger.Error(err, "Error waiting for notification on jobs channel")
 			continue
 		}
 
@@ -236,7 +253,7 @@ func (q *DBJobQueue) Enqueue(jobType string, args interface{}, dependencies []uu
 	defer func() {
 		err := tx.Rollback(context.Background())
 		if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
-			logrus.Error("error rolling back enqueue transaction: ", err)
+			q.logger.Error(err, "Error rolling back enqueue transaction")
 		}
 	}()
 
@@ -263,7 +280,7 @@ func (q *DBJobQueue) Enqueue(jobType string, args interface{}, dependencies []uu
 		return uuid.Nil, fmt.Errorf("unable to commit database transaction: %v", err)
 	}
 
-	logrus.Infof("Enqueued job of type %s with ID %s(dependencies %v)", jobType, id, dependencies)
+	q.logger.Info("Enqueued job", "job_type", jobType, "job_id", id.String(), "job_dependencies", fmt.Sprintf("%+v", dependencies))
 
 	return id, nil
 }
@@ -318,7 +335,7 @@ func (q *DBJobQueue) Dequeue(ctx context.Context, jobTypes []string, channels []
 		return uuid.Nil, uuid.Nil, nil, "", nil, fmt.Errorf("error querying the job's dependencies: %v", err)
 	}
 
-	logrus.Infof("Dequeued job of type %v with ID %s", jobType, id)
+	q.logger.Info("Dequeued job", "job_type", jobType, "job_id", id.String(), "job_dependencies", fmt.Sprintf("%+v", dependencies))
 
 	return id, token, dependencies, jobType, args, nil
 }
@@ -372,7 +389,7 @@ func (q *DBJobQueue) DequeueByID(ctx context.Context, id uuid.UUID) (uuid.UUID,
 		return uuid.Nil, nil, "", nil, fmt.Errorf("error querying the job's dependencies: %v", err)
 	}
 
-	logrus.Infof("Dequeued job of type %v with ID %s", jobType, id)
+	q.logger.Info("Dequeued job", "job_type", jobType, "job_id", id.String(), "job_dependencies", fmt.Sprintf("%+v", dependencies))
 
 	return token, dependencies, jobType, args, nil
 }
@@ -391,7 +408,7 @@ func (q *DBJobQueue) FinishJob(id uuid.UUID, result interface{}) error {
 	defer func() {
 		err = tx.Rollback(context.Background())
 		if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
-			logrus.Errorf("error rolling back finish job transaction for job %s: %v", id, err)
+			q.logger.Error(err, "Error rolling back finish job transaction", "job_id", id.String())
 		}
 
 	}()
@@ -440,7 +457,7 @@ func (q *DBJobQueue) FinishJob(id uuid.UUID, result interface{}) error {
 		return fmt.Errorf("unable to commit database transaction: %v", err)
 	}
 
-	logrus.Infof("Finished job with ID %s", id)
+	q.logger.Info("Finished job", "job_type", jobType, "job_id", id.String())
 
 	return nil
 }
@@ -462,7 +479,7 @@ func (q *DBJobQueue) CancelJob(id uuid.UUID) error {
 		return fmt.Errorf("error canceling job %s: %v", id, err)
 	}
 
-	logrus.Infof("Cancelled job with ID %s", id)
+	q.logger.Info("Cancelled job", "job_type", jobType, "job_id", id.String())
 
 	return nil
 }
@@ -560,13 +577,13 @@ func (q *DBJobQueue) Heartbeats(olderThan time.Duration) (tokens []uuid.UUID) {
 		err = rows.Scan(&t)
 		if err != nil {
 			// Log the error and try to continue with the next row
-			logrus.Error("Unable to read token from heartbeats: ", err)
+			q.logger.Error(err, "Unable to read token from heartbeats")
 			continue
 		}
 		tokens = append(tokens, t)
 	}
 	if rows.Err() != nil {
-		logrus.Error("Error reading tokens from heartbeats: ", rows.Err())
+		q.logger.Error(rows.Err(), "Error reading tokens from heartbeats")
 	}
 
 	return
@@ -582,10 +599,10 @@ func (q *DBJobQueue) RefreshHeartbeat(token uuid.UUID) {
 
 	tag, err := conn.Exec(context.Background(), sqlRefreshHeartbeat, token)
 	if err != nil {
-		logrus.Error("Error refreshing heartbeat: ", err)
+		q.logger.Error(err, "Error refreshing heartbeat")
 	}
 	if tag.RowsAffected() != 1 {
-		logrus.Error("No rows affected when refreshing heartbeat for ", token)
+		q.logger.Error(nil, "No rows affected when refreshing heartbeat", "job_token", token.String())
 	}
 }
 
diff --git a/pkg/jobqueue/jobqueue.go b/pkg/jobqueue/jobqueue.go
index ae8fad879..3d5bd8dd0 100644
--- a/pkg/jobqueue/jobqueue.go
+++ b/pkg/jobqueue/jobqueue.go
@@ -79,6 +79,18 @@ type JobQueue interface {
 	RefreshHeartbeat(token uuid.UUID)
 }
 
+// SimpleLogger provides a structured logging methods for the jobqueue library.
+type SimpleLogger interface {
+	// Info creates an info-level message and arbitrary amount of key-value string pairs which
+	// can be optionally mapped to fields by underlying implementations.
+	Info(msg string, args ...string)
+
+	// Error creates an error-level message and arbitrary amount of key-value string pairs which
+	// can be optionally mapped to fields by underlying implementations. The first error argument
+	// can be set to nil when no context error is available.
+	Error(err error, msg string, args ...string)
+}
+
 var (
 	ErrNotExist       = errors.New("job does not exist")
 	ErrNotPending     = errors.New("job is not pending")
diff --git a/templates/packer/worker.pkr.hcl b/templates/packer/worker.pkr.hcl
index 52abe8902..9f19bc9e3 100644
--- a/templates/packer/worker.pkr.hcl
+++ b/templates/packer/worker.pkr.hcl
@@ -32,6 +32,10 @@ build {
     source_ami = "ami-03debf3ebf61b20cd"
     ssh_username = "ec2-user"
     instance_type = "c6a.large"
+    aws_polling {
+      delay_seconds = 10
+      max_attempts  = 60
+    }
 
     # Set a name for the resulting AMI.
     ami_name = "${var.image_name}"
@@ -55,39 +59,39 @@ build {
     }
   }
 
-  // source "amazon-ebs.image_builder" {
-  //   name = "rhel-8-aarch64"
-
-  //   # Use a static RHEL 8.6 Cloud Access Image.
-  //   source_ami = "ami-0c84d76d81209a0e2"
-  //   ssh_username = "ec2-user"
-  //   instance_type = "c6g.large"
-  //   aws_polling {
-  //     delay_seconds = 10
-  //     max_attempts  = 50
-  //   }
-
-  //   # Set a name for the resulting AMI.
-  //   ami_name = "${var.image_name}"
-
-  //   # Apply tags to the resulting AMI/EBS snapshot.
-  //   tags = {
-  //     AppCode = "IMGB-001"
-  //     Name = "${var.image_name}"
-  //     composer_commit = "${var.composer_commit}"
-  //     os = "rhel"
-  //     os_version = "8"
-  //     arch = "aarch64"
-  //   }
-
-  //   # Ensure that the EBS snapshot used for the AMI meets our requirements.
-  //   launch_block_device_mappings {
-  //     delete_on_termination = "true"
-  //     device_name           = "/dev/sda1"
-  //     volume_size           = 10
-  //     volume_type           = "gp2"
-  //   }
-  // }
+  source "amazon-ebs.image_builder" {
+    name = "rhel-8-aarch64"
+
+    # Use a static RHEL 8.6 Cloud Access Image.
+    source_ami = "ami-0c84d76d81209a0e2"
+    ssh_username = "ec2-user"
+    instance_type = "c6g.large"
+    aws_polling {
+      delay_seconds = 10
+      max_attempts  = 60
+    }
+
+    # Set a name for the resulting AMI.
+    ami_name = "${var.image_name}"
+
+    # Apply tags to the resulting AMI/EBS snapshot.
+    tags = {
+      AppCode = "IMGB-001"
+      Name = "${var.image_name}"
+      composer_commit = "${var.composer_commit}"
+      os = "rhel"
+      os_version = "8"
+      arch = "aarch64"
+    }
+
+    # Ensure that the EBS snapshot used for the AMI meets our requirements.
+    launch_block_device_mappings {
+      delete_on_termination = "true"
+      device_name           = "/dev/sda1"
+      volume_size           = 10
+      volume_type           = "gp2"
+    }
+  }
 
   source "amazon-ebs.image_builder"  {
     name = "fedora-35-x86_64"
diff --git a/tools/appsre-worker-packer-container.sh b/tools/appsre-worker-packer-container.sh
index 35c4a8b52..7b6f77e83 100755
--- a/tools/appsre-worker-packer-container.sh
+++ b/tools/appsre-worker-packer-container.sh
@@ -19,4 +19,5 @@ image_users = [$PACKER_IMAGE_USERS]
 EOF2
 fi
 
-/usr/bin/packer build "$PACKER_ONLY_EXCEPT" /osbuild-composer/templates/packer
+# disable parallel builds as it fails consistently while waiting for AMI
+/usr/bin/packer build -parallel-builds=1 "$PACKER_ONLY_EXCEPT" /osbuild-composer/templates/packer


Test patch:
diff --git a/internal/common/slogger/logrus_test.go b/internal/common/slogger/logrus_test.go
new file mode 100644
index 000000000..2e626eeec
--- /dev/null
+++ b/internal/common/slogger/logrus_test.go
@@ -0,0 +1,63 @@
+package slogger
+
+import (
+	"bytes"
+	"errors"
+	"testing"
+
+	"github.com/sirupsen/logrus"
+	"github.com/stretchr/testify/require"
+)
+
+func makeLogrus(buf *bytes.Buffer) *logrus.Logger {
+	return &logrus.Logger{
+		Out: buf,
+		Formatter: &logrus.TextFormatter{
+			DisableTimestamp: true,
+			DisableColors:    true,
+		},
+		Hooks: make(logrus.LevelHooks),
+		Level: logrus.DebugLevel,
+	}
+
+}
+
+func TestInfo(t *testing.T) {
+	buf := &bytes.Buffer{}
+	l := makeLogrus(buf)
+	sl := NewLogrusLogger(l)
+	sl.Info("test")
+	require.Equal(t, "level=info msg=test\n", buf.String())
+}
+
+func TestError(t *testing.T) {
+	buf := &bytes.Buffer{}
+	l := makeLogrus(buf)
+	sl := NewLogrusLogger(l)
+	sl.Error(errors.New("e"), "test")
+	require.Equal(t, "level=error msg=test error=e\n", buf.String())
+}
+
+func TestErrorIsNil(t *testing.T) {
+	buf := &bytes.Buffer{}
+	l := makeLogrus(buf)
+	sl := NewLogrusLogger(l)
+	sl.Error(nil, "test")
+	require.Equal(t, "level=error msg=test\n", buf.String())
+}
+
+func TestInfoWithFields(t *testing.T) {
+	buf := &bytes.Buffer{}
+	l := makeLogrus(buf)
+	sl := NewLogrusLogger(l)
+	sl.Info("test", "key", "value")
+	require.Equal(t, "level=info msg=test key=value\n", buf.String())
+}
+
+func TestErrorWithFields(t *testing.T) {
+	buf := &bytes.Buffer{}
+	l := makeLogrus(buf)
+	sl := NewLogrusLogger(l)
+	sl.Error(errors.New("e"), "test", "key", "value")
+	require.Equal(t, "level=error msg=test error=e key=value\n", buf.String())
+}
diff --git a/test/cases/aws.sh b/test/cases/aws.sh
index b9e6832e0..cb355d0db 100755
--- a/test/cases/aws.sh
+++ b/test/cases/aws.sh
@@ -245,6 +245,10 @@ tee "${TEMPDIR}/resource-file.json" <<EOF
 }
 EOF
 
+if [ "$ARCH" == "aarch64" ]; then
+    sed -i s/t3.medium/a1.large/ "${TEMPDIR}/resource-file.json"
+fi
+
 sudo ${CONTAINER_RUNTIME} run \
     -a stdout -a stderr \
     -e AWS_ACCESS_KEY_ID="${V2_AWS_ACCESS_KEY_ID}" \