diff options
Diffstat (limited to 'pkg/api')
-rw-r--r-- | pkg/api/handlers/compat/events.go | 2 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images.go | 34 | ||||
-rw-r--r-- | pkg/api/handlers/compat/networks.go | 2 | ||||
-rw-r--r-- | pkg/api/handlers/compat/resize.go | 15 | ||||
-rw-r--r-- | pkg/api/handlers/compat/swagger.go | 7 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/images_pull.go | 2 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/networks.go | 3 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/swagger.go | 9 | ||||
-rw-r--r-- | pkg/api/server/handler_api.go | 6 | ||||
-rw-r--r-- | pkg/api/server/register_containers.go | 2 | ||||
-rw-r--r-- | pkg/api/server/register_images.go | 20 | ||||
-rw-r--r-- | pkg/api/server/register_networks.go | 13 | ||||
-rw-r--r-- | pkg/api/server/server.go | 21 |
13 files changed, 99 insertions, 37 deletions
diff --git a/pkg/api/handlers/compat/events.go b/pkg/api/handlers/compat/events.go index 405e616c5..9fbac91e0 100644 --- a/pkg/api/handlers/compat/events.go +++ b/pkg/api/handlers/compat/events.go @@ -75,7 +75,7 @@ func GetEvents(w http.ResponseWriter, r *http.Request) { coder := json.NewEncoder(w) coder.SetEscapeHTML(true) - for stream := true; stream; stream = query.Stream { + for { select { case err := <-errorChannel: if err != nil { diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index 7b336c470..ac212474b 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -168,6 +168,8 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) { query := struct { FromSrc string `schema:"fromSrc"` Changes []string `schema:"changes"` + Message string `schema:"message"` + Repo string `shchema:"repo"` }{ // This is where you can override the golang default value for one of fields } @@ -184,14 +186,15 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile")) return } + source = f.Name() if err := SaveFromBody(f, r); err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file")) } } - imageEngine := abi.ImageEngine{Libpod: runtime} - report, err := imageEngine.Import(r.Context(), entities.ImageImportOptions{Source: source, Changes: query.Changes}) + // TODO: add support for ImageImportOptions to take a platform parameter. Also import https://github.com/opencontainers/image-spec/tree/master/specs-go/v1 either here or within imageEngine.Import to get default platform + report, err := imageEngine.Import(r.Context(), entities.ImageImportOptions{Source: source, Changes: query.Changes, Message: query.Message, Reference: query.Repo}) if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to import tarball")) return @@ -224,10 +227,10 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) { query := struct { FromImage string `schema:"fromImage"` Tag string `schema:"tag"` + Platform string `schema:"platform"` }{ // This is where you can override the golang default value for one of fields } - if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return @@ -250,12 +253,36 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) { } defer auth.RemoveAuthfile(authfile) + platformSpecs := strings.Split(query.Platform, "/") // split query into its parts + + addOS := true // default assume true due to structure of if/else below + addArch := false + addVariant := false + + if len(platformSpecs) > 1 { // if we have two arguments then we have os and arch + addArch = true + if len(platformSpecs) > 2 { // if we have 3 arguments then we have os arch and variant + addVariant = true + } + } else if len(platformSpecs) == 0 { + addOS = false + } + pullOptions := &libimage.PullOptions{} pullOptions.AuthFilePath = authfile if authConf != nil { pullOptions.Username = authConf.Username pullOptions.Password = authConf.Password pullOptions.IdentityToken = authConf.IdentityToken + if addOS { // if the len is not 0 + pullOptions.OS = platformSpecs[0] + if addArch { + pullOptions.Architecture = platformSpecs[1] + } + if addVariant { + pullOptions.Variant = platformSpecs[2] + } + } } pullOptions.Writer = os.Stderr // allows for debugging on the server @@ -294,7 +321,6 @@ loop: // break out of for/select infinite loop Error string `json:"error,omitempty"` Id string `json:"id,omitempty"` // nolint } - select { case e := <-progress: switch e.Event { diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go index 77ed548d8..04f8570ff 100644 --- a/pkg/api/handlers/compat/networks.go +++ b/pkg/api/handlers/compat/networks.go @@ -414,7 +414,7 @@ func Prune(w http.ResponseWriter, r *http.Request) { type response struct { NetworksDeleted []string } - var prunedNetworks []string //nolint + prunedNetworks := []string{} for _, pr := range pruneReports { if pr.Error != nil { logrus.Error(pr.Error) diff --git a/pkg/api/handlers/compat/resize.go b/pkg/api/handlers/compat/resize.go index 23ed33a22..f65e313fc 100644 --- a/pkg/api/handlers/compat/resize.go +++ b/pkg/api/handlers/compat/resize.go @@ -46,20 +46,13 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) { utils.ContainerNotFound(w, name, err) return } - if state, err := ctnr.State(); err != nil { - utils.InternalServerError(w, errors.Wrapf(err, "cannot obtain container state")) - return - } else if state != define.ContainerStateRunning && !query.IgnoreNotRunning { - utils.Error(w, "Container not running", http.StatusConflict, - fmt.Errorf("container %q in wrong state %q", name, state.String())) - return - } - // If container is not running, ignore since this can be a race condition, and is expected if err := ctnr.AttachResize(sz); err != nil { - if errors.Cause(err) != define.ErrCtrStateInvalid || !query.IgnoreNotRunning { + if errors.Cause(err) != define.ErrCtrStateInvalid { utils.InternalServerError(w, errors.Wrapf(err, "cannot resize container")) - return + } else { + utils.Error(w, "Container not running", http.StatusConflict, err) } + return } // This is not a 204, even though we write nothing, for compatibility // reasons. diff --git a/pkg/api/handlers/compat/swagger.go b/pkg/api/handlers/compat/swagger.go index a0783e723..b773799ef 100644 --- a/pkg/api/handlers/compat/swagger.go +++ b/pkg/api/handlers/compat/swagger.go @@ -77,10 +77,3 @@ type swagCompatNetworkDisconnectRequest struct { // in:body Body struct{ types.NetworkDisconnect } } - -// Network prune -// swagger:response NetworkPruneResponse -type swagCompatNetworkPruneResponse struct { - // in:body - Body []string -} diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go index fe56aa31d..e88b53a4b 100644 --- a/pkg/api/handlers/libpod/images_pull.go +++ b/pkg/api/handlers/libpod/images_pull.go @@ -85,7 +85,7 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { var pulledImages []*libimage.Image var pullError error - runCtx, cancel := context.WithCancel(context.Background()) + runCtx, cancel := context.WithCancel(r.Context()) go func() { defer cancel() pulledImages, pullError = runtime.LibimageRuntime().Pull(runCtx, query.Reference, config.PullPolicyAlways, pullOptions) diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go index 5417f778e..e4f450e12 100644 --- a/pkg/api/handlers/libpod/networks.go +++ b/pkg/api/handlers/libpod/networks.go @@ -190,5 +190,8 @@ func Prune(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) return } + if pruneReports == nil { + pruneReports = []*entities.NetworkPruneReport{} + } utils.WriteResponse(w, http.StatusOK, pruneReports) } diff --git a/pkg/api/handlers/libpod/swagger.go b/pkg/api/handlers/libpod/swagger.go index 9450a70d9..2ac5009fc 100644 --- a/pkg/api/handlers/libpod/swagger.go +++ b/pkg/api/handlers/libpod/swagger.go @@ -95,7 +95,7 @@ type swagInfoResponse struct { // swagger:response NetworkRmReport type swagNetworkRmReport struct { // in:body - Body entities.NetworkRmReport + Body []entities.NetworkRmReport } // Network inspect @@ -119,6 +119,13 @@ type swagNetworkCreateReport struct { Body entities.NetworkCreateReport } +// Network prune +// swagger:response NetworkPruneResponse +type swagNetworkPruneResponse struct { + // in:body + Body []entities.NetworkPruneReport +} + func ServeSwagger(w http.ResponseWriter, r *http.Request) { path := DefaultPodmanSwaggerSpec if p, found := os.LookupEnv("PODMAN_SWAGGER_SPEC"); found { diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go index 28b8706a8..becc674c0 100644 --- a/pkg/api/server/handler_api.go +++ b/pkg/api/server/handler_api.go @@ -63,6 +63,12 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc { w.Header().Set("Libpod-API-Version", lv) w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")") + if s.CorsHeaders != "" { + w.Header().Set("Access-Control-Allow-Origin", s.CorsHeaders) + w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth, Connection, Upgrade, X-Registry-Config") + w.Header().Set("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS") + } + h(w, r) logrus.Debugf("APIHandler(%s) -- %s %s END", rid, r.Method, r.URL.String()) } diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index aa999905e..88ebb4df5 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -1364,6 +1364,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // $ref: "#/responses/ok" // 404: // $ref: "#/responses/NoSuchContainer" + // 409: + // $ref: "#/responses/ConflictError" // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/resize"), s.APIHandler(compat.ResizeTTY)).Methods(http.MethodPost) diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 9634bd83b..b28818768 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -28,15 +28,28 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - in: query // name: fromImage // type: string - // description: needs description + // description: Name of the image to pull. The name may include a tag or digest. This parameter may only be used when pulling an image. The pull is cancelled if the HTTP connection is closed. // - in: query // name: fromSrc // type: string - // description: needs description + // description: Source to import. The value may be a URL from which the image can be retrieved or - to read the image from the request body. This parameter may only be used when importing an image + // - in: query + // name: repo + // type: string + // description: Repository name given to an image when it is imported. The repo may include a tag. This parameter may only be used when importing an image. // - in: query // name: tag // type: string - // description: needs description + // description: Tag or digest. If empty when pulling an image, this causes all tags for the given image to be pulled. + // - in: query + // name: message + // type: string + // description: Set commit message for imported image. + // - in: query + // name: platform + // type: string + // description: Platform in the format os[/arch[/variant]] + // default: "" // - in: header // name: X-Registry-Auth // type: string @@ -45,6 +58,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // name: request // schema: // type: string + // format: binary // description: Image content if fromSrc parameter was used // responses: // 200: diff --git a/pkg/api/server/register_networks.go b/pkg/api/server/register_networks.go index 9a5ccb789..d122c6a36 100644 --- a/pkg/api/server/register_networks.go +++ b/pkg/api/server/register_networks.go @@ -180,9 +180,12 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // 200: // description: OK // schema: - // type: array - // items: - // type: string + // type: object + // properties: + // NetworksDeleted: + // type: array + // items: + // type: string // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/networks/prune"), s.APIHandler(compat.Prune)).Methods(http.MethodPost) @@ -241,7 +244,9 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // tags: // - networks // summary: List networks - // description: Display summary of network configurations + // description: | + // Display summary of network configurations. + // - In a 200 response, all of the fields named Bytes are returned as a Base64 encoded string. // parameters: // - in: query // name: filters diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go index 972541bc6..1e8faf8f5 100644 --- a/pkg/api/server/server.go +++ b/pkg/api/server/server.go @@ -34,10 +34,12 @@ type APIServer struct { context.CancelFunc // Stop APIServer idleTracker *idle.Tracker // Track connections to support idle shutdown pprof *http.Server // Sidecar http server for providing performance data + CorsHeaders string // Inject CORS headers to each request } // Number of seconds to wait for next request, if exceeded shutdown server const ( + DefaultCorsHeaders = "" DefaultServiceDuration = 300 * time.Second UnlimitedServiceDuration = 0 * time.Second ) @@ -45,17 +47,22 @@ const ( // shutdownOnce ensures Shutdown() may safely be called from several go routines var shutdownOnce sync.Once +type Options struct { + Timeout time.Duration + CorsHeaders string +} + // NewServer will create and configure a new API server with all defaults func NewServer(runtime *libpod.Runtime) (*APIServer, error) { - return newServer(runtime, DefaultServiceDuration, nil) + return newServer(runtime, DefaultServiceDuration, nil, DefaultCorsHeaders) } // NewServerWithSettings will create and configure a new API server using provided settings -func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) { - return newServer(runtime, duration, listener) +func NewServerWithSettings(runtime *libpod.Runtime, listener *net.Listener, opts Options) (*APIServer, error) { + return newServer(runtime, opts.Timeout, listener, opts.CorsHeaders) } -func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) { +func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener, corsHeaders string) (*APIServer, error) { // If listener not provided try socket activation protocol if listener == nil { if _, found := os.LookupEnv("LISTEN_PID"); !found { @@ -71,6 +78,11 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li } listener = &listeners[0] } + if corsHeaders == "" { + logrus.Debug("CORS Headers were not set") + } else { + logrus.Debugf("CORS Headers were set to %s", corsHeaders) + } logrus.Infof("API server listening on %q", (*listener).Addr()) router := mux.NewRouter().UseEncodedPath() @@ -88,6 +100,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li idleTracker: idle, Listener: *listener, Runtime: runtime, + CorsHeaders: corsHeaders, } router.NotFoundHandler = http.HandlerFunc( |