@@ -3,12 +3,17 @@ package container
33import (
44 "context"
55 "encoding/json"
6+ "errors"
7+ "fmt"
68 "io"
9+ "log/slog"
710 "net"
811 "net/http"
12+ "os"
913 "strings"
1014
1115 "github.com/docker/docker/api/types/image"
16+ "github.com/google/go-querystring/query"
1217)
1318
1419type ResponsePruneImage struct {
@@ -21,6 +26,10 @@ type SocketClient struct {
2126 Client * http.Client
2227}
2328
29+ func NewDefaultLibPodHTTPClient () * SocketClient {
30+ return NewLibPodHTTPClient (findContainerEngineSocket ())
31+ }
32+
2433func NewLibPodHTTPClient (sock string ) * SocketClient {
2534 httpc := http.Client {
2635 Transport : & http.Transport {
@@ -40,6 +49,19 @@ func (c *SocketClient) resolveURL(path string) string {
4049 return strings .Join ([]string {c .BaseURL , strings .TrimPrefix (path , "/" )}, "/" )
4150}
4251
52+ var ErrPodmanAPIError = errors .New ("podman api not available" )
53+
54+ func (c * SocketClient ) Test (ctx context.Context ) error {
55+ r , err := c .Client .Get (c .resolveURL ("info" ))
56+ if err != nil {
57+ return err
58+ }
59+ if r .StatusCode != 200 {
60+ return ErrPodmanAPIError
61+ }
62+ return nil
63+ }
64+
4365// Prune all images and return object in same format as the docker prune response
4466func (c * SocketClient ) PruneImages (body io.Reader ) (report image.PruneReport , err error ) {
4567 r , err := c .Client .Post (c .resolveURL ("images/prune?all=true" ), "application/json" , body )
@@ -69,3 +91,68 @@ func (c *SocketClient) PruneImages(body io.Reader) (report image.PruneReport, er
6991 report .SpaceReclaimed = spaceReclaimed
7092 return
7193}
94+
95+ type PodmanAPIPullOptions struct {
96+ AllTags * bool `url:"allTags,omitempty"`
97+ Quiet * bool `url:"quiet,omitempty"`
98+ Policy string `url:"policy,omitempty"`
99+ Reference string `url:"reference"`
100+ }
101+
102+ func (po * PodmanAPIPullOptions ) WithPolicy (v string ) * PodmanAPIPullOptions {
103+ po .Policy = v
104+ return po
105+ }
106+
107+ func (po * PodmanAPIPullOptions ) WithAllTags (v bool ) * PodmanAPIPullOptions {
108+ po .AllTags = & v
109+ return po
110+ }
111+
112+ func (po * PodmanAPIPullOptions ) WithQuiet (v bool ) * PodmanAPIPullOptions {
113+ po .Quiet = & v
114+ return po
115+ }
116+
117+ type PodmanPullOptions struct {
118+ image.PullOptions
119+
120+ Quiet bool
121+ }
122+
123+ func (c * SocketClient ) PullImages (ctx context.Context , imageRef string , alwaysPull bool , pullOptions PodmanPullOptions ) error {
124+ options := PodmanAPIPullOptions {
125+ Reference : imageRef ,
126+ }
127+ options .WithQuiet (pullOptions .Quiet )
128+ if alwaysPull {
129+ options .WithPolicy ("always" )
130+ }
131+
132+ queryParams , err := query .Values (options )
133+ if err != nil {
134+ return err
135+ }
136+
137+ req , err := http .NewRequestWithContext (ctx , http .MethodPost , c .resolveURL (fmt .Sprintf ("images/pull?%s" , queryParams .Encode ())), nil )
138+ if err != nil {
139+ return err
140+ }
141+
142+ if pullOptions .RegistryAuth != "" {
143+ req .Header .Set ("X-Registry-Auth" , pullOptions .RegistryAuth )
144+ }
145+
146+ r , err := c .Client .Do (req )
147+ if err != nil {
148+ return err
149+ }
150+
151+ defer r .Body .Close ()
152+ if _ , ioErr := io .Copy (os .Stderr , r .Body ); ioErr != nil {
153+ slog .Warn ("Could not write to stderr." , "err" , ioErr )
154+ }
155+
156+ slog .Info ("Podman API response was successful." , "status" , r .Status )
157+ return nil
158+ }
0 commit comments