feat(delivery): add AWX API client

Implement AWXClient with Launch, GetJob, and Cancel methods for
orchestrating Ansible job templates via AWX REST API. Uses Bearer
token auth with 30s timeout. Includes unit tests with mock transport.

Relates-to: #97
This commit is contained in:
mac
2026-07-23 12:04:15 +08:00
parent 76583c6766
commit 81a94322f7
2 changed files with 156 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
package service
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"testing"
)
type roundTripFunc func(*http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) }
func TestAWXClientLaunchAndGetJob(t *testing.T) {
client := NewAWXClient("https://awx.example", "token")
client.client.Transport = roundTripFunc(func(r *http.Request) (*http.Response, error) {
if r.Header.Get("Authorization") != "Bearer token" {
t.Fatalf("missing auth header")
}
job := AWXJob{ID: 42, Status: "pending"}
if r.URL.Path == "/api/v2/jobs/42/" {
job.Status = "successful"
} else if r.URL.Path != "/api/v2/job_templates/7/launch/" {
t.Fatalf("unexpected path %s", r.URL.Path)
}
raw, _ := json.Marshal(job)
return &http.Response{StatusCode: http.StatusOK, Status: "200 OK", Body: io.NopCloser(bytes.NewReader(raw)), Header: make(http.Header)}, nil
})
job, err := client.Launch(context.Background(), 7, AWXLaunchRequest{InventoryID: 3, ExtraVars: map[string]any{"task_id": "t"}})
if err != nil || job.ID != 42 {
t.Fatalf("launch = %#v, err=%v", job, err)
}
job, err = client.GetJob(context.Background(), "42")
if err != nil || job.Status != "successful" {
t.Fatalf("get job = %#v, err=%v", job, err)
}
}