aboutsummaryrefslogtreecommitdiff
path: root/pkg/api/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api/handlers')
-rw-r--r--pkg/api/handlers/compat/images.go32
-rw-r--r--pkg/api/handlers/compat/images_push.go1
-rw-r--r--pkg/api/handlers/compat/networks.go54
-rw-r--r--pkg/api/handlers/libpod/containers_create.go3
-rw-r--r--pkg/api/handlers/libpod/images.go71
-rw-r--r--pkg/api/handlers/libpod/images_push.go144
6 files changed, 195 insertions, 110 deletions
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 2f8d151d8..39bd165d6 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -23,6 +23,7 @@ import (
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/domain/infra/abi"
"github.com/containers/storage"
+ "github.com/docker/docker/pkg/jsonmessage"
"github.com/gorilla/schema"
"github.com/opencontainers/go-digest"
"github.com/sirupsen/logrus"
@@ -325,16 +326,8 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
loop: // break out of for/select infinite loop
for {
- var report struct {
- Stream string `json:"stream,omitempty"`
- Status string `json:"status,omitempty"`
- Progress struct {
- Current uint64 `json:"current,omitempty"`
- Total int64 `json:"total,omitempty"`
- } `json:"progressDetail,omitempty"`
- Error string `json:"error,omitempty"`
- Id string `json:"id,omitempty"` //nolint:revive,stylecheck
- }
+ report := jsonmessage.JSONMessage{}
+ report.Progress = &jsonmessage.JSONProgress{}
select {
case e := <-progress:
switch e.Event {
@@ -342,14 +335,15 @@ loop: // break out of for/select infinite loop
report.Status = "Pulling fs layer"
case types.ProgressEventRead:
report.Status = "Downloading"
- report.Progress.Current = e.Offset
+ report.Progress.Current = int64(e.Offset)
report.Progress.Total = e.Artifact.Size
+ report.ProgressMessage = report.Progress.String()
case types.ProgressEventSkipped:
report.Status = "Already exists"
case types.ProgressEventDone:
report.Status = "Download complete"
}
- report.Id = e.Artifact.Digest.Encoded()[0:12]
+ report.ID = e.Artifact.Digest.Encoded()[0:12]
if err := enc.Encode(report); err != nil {
logrus.Warnf("Failed to json encode error %q", err.Error())
}
@@ -358,7 +352,11 @@ loop: // break out of for/select infinite loop
err := pullRes.err
pulledImages := pullRes.images
if err != nil {
- report.Error = err.Error()
+ msg := err.Error()
+ report.Error = &jsonmessage.JSONError{
+ Message: msg,
+ }
+ report.ErrorMessage = msg
} else {
if len(pulledImages) > 0 {
img := pulledImages[0].ID()
@@ -367,9 +365,13 @@ loop: // break out of for/select infinite loop
} else {
report.Status = "Download complete"
}
- report.Id = img[0:12]
+ report.ID = img[0:12]
} else {
- report.Error = "internal error: no images pulled"
+ msg := "internal error: no images pulled"
+ report.Error = &jsonmessage.JSONError{
+ Message: msg,
+ }
+ report.ErrorMessage = msg
}
}
if err := enc.Encode(report); err != nil {
diff --git a/pkg/api/handlers/compat/images_push.go b/pkg/api/handlers/compat/images_push.go
index bb82ef10d..f29808124 100644
--- a/pkg/api/handlers/compat/images_push.go
+++ b/pkg/api/handlers/compat/images_push.go
@@ -156,6 +156,7 @@ loop: // break out of for/select infinite loop
Current: int64(e.Offset),
Total: e.Artifact.Size,
}
+ report.ProgressMessage = report.Progress.String()
case types.ProgressEventSkipped:
report.Status = "Layer already exists"
case types.ProgressEventDone:
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index 65177218a..29d1398cf 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -23,6 +23,13 @@ import (
"github.com/sirupsen/logrus"
)
+func normalizeNetworkName(rt *libpod.Runtime, name string) (string, bool) {
+ if name == nettypes.BridgeNetworkDriver {
+ return rt.Network().DefaultNetworkName(), true
+ }
+ return name, false
+}
+
func InspectNetwork(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
@@ -44,13 +51,13 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
utils.Error(w, http.StatusBadRequest, define.ErrInvalidArg)
return
}
- name := utils.GetName(r)
+ name, changed := normalizeNetworkName(runtime, utils.GetName(r))
net, err := runtime.Network().NetworkInspect(name)
if err != nil {
utils.NetworkNotFound(w, name, err)
return
}
- report, err := convertLibpodNetworktoDockerNetwork(runtime, net)
+ report, err := convertLibpodNetworktoDockerNetwork(runtime, &net, changed)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -58,7 +65,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, report)
}
-func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network nettypes.Network) (*types.NetworkResource, error) {
+func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network *nettypes.Network, changeDefaultName bool) (*types.NetworkResource, error) {
cons, err := runtime.GetAllContainers()
if err != nil {
return nil, err
@@ -107,11 +114,15 @@ func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network nettyp
Config: ipamConfigs,
}
+ name := network.Name
+ if changeDefaultName && name == runtime.Network().DefaultNetworkName() {
+ name = nettypes.BridgeNetworkDriver
+ }
report := types.NetworkResource{
- Name: network.Name,
- ID: network.ID,
- Driver: network.Driver,
- // TODO add Created: ,
+ Name: name,
+ ID: network.ID,
+ Driver: network.Driver,
+ Created: network.Created,
Internal: network.Internal,
EnableIPv6: network.IPv6Enabled,
Labels: network.Labels,
@@ -149,7 +160,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
}
reports := make([]*types.NetworkResource, 0, len(nets))
for _, net := range nets {
- report, err := convertLibpodNetworktoDockerNetwork(runtime, net)
+ report, err := convertLibpodNetworktoDockerNetwork(runtime, &net, true)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -182,27 +193,22 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
network.Options = make(map[string]string)
- // TODO: we should consider making this constants in c/common/libnetwork/types
+ // dockers bridge networks are always isolated from each other
+ if network.Driver == nettypes.BridgeNetworkDriver {
+ network.Options[nettypes.IsolateOption] = "true"
+ }
+
for opt, optVal := range networkCreate.Options {
switch opt {
- case "mtu":
+ case nettypes.MTUOption:
fallthrough
case "com.docker.network.driver.mtu":
- if network.Driver == nettypes.BridgeNetworkDriver {
- network.Options["mtu"] = optVal
- }
- case "icc":
- fallthrough
- case "com.docker.network.bridge.enable_icc":
- // TODO: needs to be implemented
- if network.Driver == nettypes.BridgeNetworkDriver {
- responseWarning = "com.docker.network.bridge.enable_icc is not currently implemented"
- }
+ network.Options[nettypes.MTUOption] = optVal
case "com.docker.network.bridge.name":
if network.Driver == nettypes.BridgeNetworkDriver {
network.NetworkInterface = optVal
}
- case "mode":
+ case nettypes.ModeOption:
if network.Driver == nettypes.MacVLANNetworkDriver || network.Driver == nettypes.IPVLANNetworkDriver {
network.Options[opt] = optVal
}
@@ -305,7 +311,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
Timeout: query.Timeout,
}
- name := utils.GetName(r)
+ name, _ := normalizeNetworkName(runtime, utils.GetName(r))
reports, err := ic.NetworkRm(r.Context(), []string{name}, options)
if err != nil {
utils.Error(w, http.StatusInternalServerError, err)
@@ -340,7 +346,7 @@ func Connect(w http.ResponseWriter, r *http.Request) {
netOpts := nettypes.PerNetworkOptions{}
- name := utils.GetName(r)
+ name, _ := normalizeNetworkName(runtime, utils.GetName(r))
if netConnect.EndpointConfig != nil {
if netConnect.EndpointConfig.Aliases != nil {
netOpts.Aliases = netConnect.EndpointConfig.Aliases
@@ -416,7 +422,7 @@ func Disconnect(w http.ResponseWriter, r *http.Request) {
return
}
- name := utils.GetName(r)
+ name, _ := normalizeNetworkName(runtime, utils.GetName(r))
err := runtime.DisconnectContainerFromNetwork(netDisconnect.Container, name, netDisconnect.Force)
if err != nil {
if errors.Is(err, define.ErrNoSuchCtr) {
diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go
index e4964d602..1307c267a 100644
--- a/pkg/api/handlers/libpod/containers_create.go
+++ b/pkg/api/handlers/libpod/containers_create.go
@@ -31,6 +31,9 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
ContainerNetworkConfig: specgen.ContainerNetworkConfig{
UseImageHosts: conf.Containers.NoHosts,
},
+ ContainerSecurityConfig: specgen.ContainerSecurityConfig{
+ Umask: conf.Containers.Umask,
+ },
}
if err := json.NewDecoder(r.Body).Decode(&sg); err != nil {
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index ed1c65f8e..67943ecf1 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -1,7 +1,6 @@
package libpod
import (
- "context"
"errors"
"fmt"
"io"
@@ -14,13 +13,11 @@ import (
"github.com/containers/buildah"
"github.com/containers/common/libimage"
"github.com/containers/image/v5/manifest"
- "github.com/containers/image/v5/types"
"github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/api/handlers"
"github.com/containers/podman/v4/pkg/api/handlers/utils"
api "github.com/containers/podman/v4/pkg/api/types"
- "github.com/containers/podman/v4/pkg/auth"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/domain/entities/reports"
"github.com/containers/podman/v4/pkg/domain/infra/abi"
@@ -416,74 +413,6 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, report)
}
-// PushImage is the handler for the compat http endpoint for pushing images.
-func PushImage(w http.ResponseWriter, r *http.Request) {
- decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
- runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
-
- query := struct {
- All bool `schema:"all"`
- Destination string `schema:"destination"`
- Format string `schema:"format"`
- RemoveSignatures bool `schema:"removeSignatures"`
- TLSVerify bool `schema:"tlsVerify"`
- }{
- // 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, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
- return
- }
-
- source := strings.TrimSuffix(utils.GetName(r), "/push") // GetName returns the entire path
- if _, err := utils.ParseStorageReference(source); err != nil {
- utils.Error(w, http.StatusBadRequest, err)
- return
- }
-
- destination := query.Destination
- if destination == "" {
- destination = source
- }
-
- if err := utils.IsRegistryReference(destination); err != nil {
- utils.Error(w, http.StatusBadRequest, err)
- return
- }
-
- authconf, authfile, err := auth.GetCredentials(r)
- if err != nil {
- utils.Error(w, http.StatusBadRequest, err)
- return
- }
- defer auth.RemoveAuthfile(authfile)
- var username, password string
- if authconf != nil {
- username = authconf.Username
- password = authconf.Password
- }
- options := entities.ImagePushOptions{
- All: query.All,
- Authfile: authfile,
- Format: query.Format,
- Password: password,
- Quiet: true,
- RemoveSignatures: query.RemoveSignatures,
- Username: username,
- }
- if _, found := r.URL.Query()["tlsVerify"]; found {
- options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
- }
-
- imageEngine := abi.ImageEngine{Libpod: runtime}
- if err := imageEngine.Push(context.Background(), source, destination, options); err != nil {
- utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err))
- return
- }
-
- utils.WriteResponse(w, http.StatusOK, "")
-}
-
func CommitContainer(w http.ResponseWriter, r *http.Request) {
var (
destImage string
diff --git a/pkg/api/handlers/libpod/images_push.go b/pkg/api/handlers/libpod/images_push.go
new file mode 100644
index 000000000..f427dc01b
--- /dev/null
+++ b/pkg/api/handlers/libpod/images_push.go
@@ -0,0 +1,144 @@
+package libpod
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/containers/image/v5/types"
+ "github.com/containers/podman/v4/libpod"
+ "github.com/containers/podman/v4/pkg/api/handlers/utils"
+ api "github.com/containers/podman/v4/pkg/api/types"
+ "github.com/containers/podman/v4/pkg/auth"
+ "github.com/containers/podman/v4/pkg/channel"
+ "github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/containers/podman/v4/pkg/domain/infra/abi"
+ "github.com/gorilla/schema"
+ "github.com/sirupsen/logrus"
+)
+
+// PushImage is the handler for the compat http endpoint for pushing images.
+func PushImage(w http.ResponseWriter, r *http.Request) {
+ decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
+ runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
+
+ query := struct {
+ All bool `schema:"all"`
+ Destination string `schema:"destination"`
+ Format string `schema:"format"`
+ RemoveSignatures bool `schema:"removeSignatures"`
+ TLSVerify bool `schema:"tlsVerify"`
+ Quiet bool `schema:"quiet"`
+ }{
+ // #14971: older versions did not sent *any* data, so we need
+ // to be quiet by default to remain backwards compatible
+ Quiet: true,
+ }
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
+ return
+ }
+
+ source := strings.TrimSuffix(utils.GetName(r), "/push") // GetName returns the entire path
+ if _, err := utils.ParseStorageReference(source); err != nil {
+ utils.Error(w, http.StatusBadRequest, err)
+ return
+ }
+
+ destination := query.Destination
+ if destination == "" {
+ destination = source
+ }
+
+ if err := utils.IsRegistryReference(destination); err != nil {
+ utils.Error(w, http.StatusBadRequest, err)
+ return
+ }
+
+ authconf, authfile, err := auth.GetCredentials(r)
+ if err != nil {
+ utils.Error(w, http.StatusBadRequest, err)
+ return
+ }
+ defer auth.RemoveAuthfile(authfile)
+
+ var username, password string
+ if authconf != nil {
+ username = authconf.Username
+ password = authconf.Password
+ }
+ options := entities.ImagePushOptions{
+ All: query.All,
+ Authfile: authfile,
+ Format: query.Format,
+ Password: password,
+ Quiet: true,
+ RemoveSignatures: query.RemoveSignatures,
+ Username: username,
+ }
+
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+
+ imageEngine := abi.ImageEngine{Libpod: runtime}
+
+ // Let's keep thing simple when running in quiet mode and push directly.
+ if query.Quiet {
+ if err := imageEngine.Push(context.Background(), source, destination, options); err != nil {
+ utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err))
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, "")
+ return
+ }
+
+ writer := channel.NewWriter(make(chan []byte))
+ defer writer.Close()
+ options.Writer = writer
+
+ pushCtx, pushCancel := context.WithCancel(r.Context())
+ var pushError error
+ go func() {
+ defer pushCancel()
+ pushError = imageEngine.Push(pushCtx, source, destination, options)
+ }()
+
+ flush := func() {
+ if flusher, ok := w.(http.Flusher); ok {
+ flusher.Flush()
+ }
+ }
+
+ w.WriteHeader(http.StatusOK)
+ w.Header().Set("Content-Type", "application/json")
+ flush()
+
+ enc := json.NewEncoder(w)
+ enc.SetEscapeHTML(true)
+ for {
+ var report entities.ImagePushReport
+ select {
+ case s := <-writer.Chan():
+ report.Stream = string(s)
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to encode json: %v", err)
+ }
+ flush()
+ case <-pushCtx.Done():
+ if pushError != nil {
+ report.Error = pushError.Error()
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to encode json: %v", err)
+ }
+ }
+ flush()
+ return
+ case <-r.Context().Done():
+ // Client has closed connection
+ return
+ }
+ }
+}