diff --git a/cmd/containerd-idp-nydus/main.go b/cmd/containerd-idp-nydus/main.go new file mode 100644 index 0000000000..21f8e6a780 --- /dev/null +++ b/cmd/containerd-idp-nydus/main.go @@ -0,0 +1,79 @@ +package main + +import ( + "bytes" + "context" + "net" + "net/http" + "os" + "time" + + "github.com/sirupsen/logrus" +) + +const nydusSnapshotterAuthEndpoint = "/api/v1/remote/auth" +const defaultNydusSystemControllerAddress = "/var/run/containerd-nydus/system.sock" + +type ImagePullCreds struct { + Host string `json:"host"` + User string `json:"user"` + Secret string `json:"secret"` +} + +func buildTransport(sock string) http.RoundTripper { + return &http.Transport{ + MaxIdleConns: 10, + IdleConnTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { + dialer := &net.Dialer{ + Timeout: 5 * time.Second, + KeepAlive: 5 * time.Second, + } + return dialer.DialContext(ctx, "unix", sock) + }, + } +} + +func NewClient(sock string) http.Client { + transport := buildTransport(sock) + return http.Client{ + Timeout: 20 * time.Second, + Transport: transport, + } +} + +func main() { + logF, err := os.OpenFile("/var/log/containerd-idp-nydus.log", os.O_RDWR|os.O_CREATE, 0600) + if err != nil { + return + } + + logrus.SetOutput(logF) + + buf := make([]byte, 4096) + _, err = os.Stdin.Read(buf) + if err != nil { + logrus.Fatalf("Receive credential error, %v", err) + } + + client := NewClient(defaultNydusSystemControllerAddress) + + body := bytes.NewBuffer(buf) + url := "http://unix" + nydusSnapshotterAuthEndpoint + req, err := http.NewRequest(http.MethodPut, url, body) + if err != nil { + logrus.Fatalf("new request error, %v", err) + } + + req.Header.Add("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + logrus.Fatalf("Send credentials error, %v", err) + } + + defer resp.Body.Close() + + return +} diff --git a/pkg/system/system.go b/pkg/system/system.go index 03cdd219cd..65ee020a49 100644 --- a/pkg/system/system.go +++ b/pkg/system/system.go @@ -39,6 +39,7 @@ const ( // it's very helpful to check daemon's record in database. endpointDaemonRecords string = "/api/v1/daemons/records" endpointDaemonsUpgrade string = "/api/v1/daemons/upgrade" + endpointRemoteAuth string = "/api/v1/remote/auth" ) const defaultErrorCode string = "Unknown" @@ -65,6 +66,12 @@ type upgradeRequest struct { Policy string `json:"policy"` } +type ImagePullCreds struct { + Host string `json:"host"` + User string `json:"user"` + Secret string `json:"secret"` +} + type errorMessage struct { Code string `json:"code"` Message string `json:"message"` @@ -152,6 +159,7 @@ func (sc *Controller) registerRouter() { sc.router.HandleFunc(endpointDaemons, sc.describeDaemons()).Methods(http.MethodGet) sc.router.HandleFunc(endpointDaemonsUpgrade, sc.upgradeDaemons()).Methods(http.MethodPut) sc.router.HandleFunc(endpointDaemonRecords, sc.getDaemonRecords()).Methods(http.MethodGet) + sc.router.HandleFunc(endpointRemoteAuth, sc.storeRemoteAuth()).Methods(http.MethodPut) } func (sc *Controller) describeDaemons() func(w http.ResponseWriter, r *http.Request) { @@ -210,6 +218,30 @@ func (sc *Controller) getDaemonRecords() func(w http.ResponseWriter, r *http.Req } } +func (sc *Controller) storeRemoteAuth() func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + var err error + var statusCode int + var creds ImagePullCreds + + defer func() { + if err != nil { + m := newErrorMessage(err.Error()) + http.Error(w, m.encode(), statusCode) + } + }() + + err = json.NewDecoder(r.Body).Decode(&creds) + if err != nil { + log.L.Errorf("request %v, decode error %s", r, err) + statusCode = http.StatusBadRequest + return + } + + log.L.Infof("Stored registry credential %+v", creds) + } +} + // PUT /api/v1/nydusd/upgrade // body: {"nydusd_path": "/path/to/new/nydusd", "version": "v2.2.1", "policy": "rolling"} // Possible policy: rolling, immediate