mirror of https://github.com/containers/podman.git
Merge pull request #11517 from jwhonce/issues/10053
Refactor API server emphasis on logging
This commit is contained in:
commit
f785d8d194
1
go.mod
1
go.mod
|
@ -35,6 +35,7 @@ require (
|
||||||
github.com/godbus/dbus/v5 v5.0.5
|
github.com/godbus/dbus/v5 v5.0.5
|
||||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
|
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/gorilla/schema v1.2.0
|
github.com/gorilla/schema v1.2.0
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
|
|
1
go.sum
1
go.sum
|
@ -499,6 +499,7 @@ github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3i
|
||||||
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||||
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo=
|
||||||
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||||
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
docker "github.com/docker/docker/api/types"
|
docker "github.com/docker/docker/api/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -37,7 +38,7 @@ func Auth(w http.ResponseWriter, r *http.Request) {
|
||||||
skipTLS = types.NewOptionalBool(true)
|
skipTLS = types.NewOptionalBool(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
sysCtx := runtime.SystemContext()
|
sysCtx := runtime.SystemContext()
|
||||||
sysCtx.DockerInsecureSkipTLSVerify = skipTLS
|
sysCtx.DockerInsecureSkipTLSVerify = skipTLS
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,14 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Changes(w http.ResponseWriter, r *http.Request) {
|
func Changes(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Parent string `schema:"parent"`
|
Parent string `schema:"parent"`
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/filters"
|
"github.com/containers/podman/v3/pkg/domain/filters"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
@ -31,7 +32,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Force bool `schema:"force"`
|
Force bool `schema:"force"`
|
||||||
Ignore bool `schema:"ignore"`
|
Ignore bool `schema:"ignore"`
|
||||||
|
@ -63,7 +64,7 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
options.Volumes = query.DockerVolumes
|
options.Volumes = query.DockerVolumes
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
// Now use the ABI implementation to prevent us from having duplicate
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
// code.
|
// code.
|
||||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
@ -92,8 +93,8 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListContainers(w http.ResponseWriter, r *http.Request) {
|
func ListContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
Limit int `schema:"limit"`
|
Limit int `schema:"limit"`
|
||||||
|
@ -168,8 +169,8 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetContainer(w http.ResponseWriter, r *http.Request) {
|
func GetContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Size bool `schema:"size"`
|
Size bool `schema:"size"`
|
||||||
}{
|
}{
|
||||||
|
@ -197,8 +198,8 @@ func GetContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func KillContainer(w http.ResponseWriter, r *http.Request) {
|
func KillContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
// /{version}/containers/(name)/kill
|
// /{version}/containers/(name)/kill
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Signal string `schema:"signal"`
|
Signal string `schema:"signal"`
|
||||||
}{
|
}{
|
||||||
|
@ -584,8 +585,8 @@ func formatCapabilities(slice []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenameContainer(w http.ResponseWriter, r *http.Request) {
|
func RenameContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
|
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
query := struct {
|
query := struct {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/copy"
|
"github.com/containers/podman/v3/pkg/copy"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
@ -18,8 +19,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Archive(w http.ResponseWriter, r *http.Request) {
|
func Archive(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
|
|
|
@ -7,14 +7,15 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
"github.com/containers/podman/v3/pkg/api/server/idle"
|
"github.com/containers/podman/v3/pkg/api/server/idle"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AttachContainer(w http.ResponseWriter, r *http.Request) {
|
func AttachContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
DetachKeys string `schema:"detachKeys"`
|
DetachKeys string `schema:"detachKeys"`
|
||||||
|
@ -104,7 +105,7 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if <-hijackChan {
|
if <-hijackChan {
|
||||||
// If connection was Hijacked, we have to signal it's being closed
|
// If connection was Hijacked, we have to signal it's being closed
|
||||||
t := r.Context().Value("idletracker").(*idle.Tracker)
|
t := r.Context().Value(api.IdleTrackerKey).(*idle.Tracker)
|
||||||
defer t.Close()
|
defer t.Close()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/podman/v3/pkg/specgen"
|
"github.com/containers/podman/v3/pkg/specgen"
|
||||||
|
@ -18,8 +19,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Name string `schema:"name"`
|
Name string `schema:"name"`
|
||||||
}{
|
}{
|
||||||
|
|
|
@ -7,11 +7,12 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExportContainer(w http.ResponseWriter, r *http.Request) {
|
func ExportContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
con, err := runtime.LookupContainer(name)
|
con, err := runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/logs"
|
"github.com/containers/podman/v3/libpod/logs"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -20,8 +21,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
|
func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Follow bool `schema:"follow"`
|
Follow bool `schema:"follow"`
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PauseContainer(w http.ResponseWriter, r *http.Request) {
|
func PauseContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
// /{version}/containers/(name)/pause
|
// /{version}/containers/(name)/pause
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities/reports"
|
"github.com/containers/podman/v3/pkg/domain/entities/reports"
|
||||||
"github.com/containers/podman/v3/pkg/domain/filters"
|
"github.com/containers/podman/v3/pkg/domain/filters"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
@ -14,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func PruneContainers(w http.ResponseWriter, r *http.Request) {
|
func PruneContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
filtersMap, err := util.PrepareFilters(r)
|
filtersMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
|
@ -65,7 +66,7 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PruneContainersHelper(r *http.Request, filterFuncs []libpod.ContainerFilter) ([]*reports.PruneReport, error) {
|
func PruneContainersHelper(r *http.Request, filterFuncs []libpod.ContainerFilter) ([]*reports.PruneReport, error) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
report, err := runtime.PruneContainers(filterFuncs)
|
report, err := runtime.PruneContainers(filterFuncs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
|
@ -13,8 +14,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func RestartContainer(w http.ResponseWriter, r *http.Request) {
|
func RestartContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
// Now use the ABI implementation to prevent us from having duplicate
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
// code.
|
// code.
|
||||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package compat
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
|
@ -12,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func StartContainer(w http.ResponseWriter, r *http.Request) {
|
func StartContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
DetachKeys string `schema:"detachKeys"`
|
DetachKeys string `schema:"detachKeys"`
|
||||||
}{
|
}{
|
||||||
|
@ -26,7 +27,7 @@ func StartContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
// TODO - start does not support adding detach keys
|
// TODO - start does not support adding detach keys
|
||||||
logrus.Info("the detach keys parameter is not supported on start container")
|
logrus.Info("the detach keys parameter is not supported on start container")
|
||||||
}
|
}
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
con, err := runtime.LookupContainer(name)
|
con, err := runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/cgroups"
|
"github.com/containers/podman/v3/pkg/cgroups"
|
||||||
docker "github.com/docker/docker/api/types"
|
docker "github.com/docker/docker/api/types"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
|
@ -18,8 +19,8 @@ import (
|
||||||
const DefaultStatsPeriod = 5 * time.Second
|
const DefaultStatsPeriod = 5 * time.Second
|
||||||
|
|
||||||
func StatsContainer(w http.ResponseWriter, r *http.Request) {
|
func StatsContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Stream bool `schema:"stream"`
|
Stream bool `schema:"stream"`
|
||||||
|
@ -64,7 +65,7 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
coder := json.NewEncoder(w)
|
coder := json.NewEncoder(w)
|
||||||
// Write header and content type.
|
// Write header and content type.
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
if flusher, ok := w.(http.Flusher); ok {
|
if flusher, ok := w.(http.Flusher); ok {
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
|
@ -13,8 +14,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func StopContainer(w http.ResponseWriter, r *http.Request) {
|
func StopContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
// Now use the ABI implementation to prevent us from having duplicate
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
// code.
|
// code.
|
||||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
|
@ -7,13 +7,14 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TopContainer(w http.ResponseWriter, r *http.Request) {
|
func TopContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
|
|
||||||
defaultValue := "-ef"
|
defaultValue := "-ef"
|
||||||
if utils.IsLibpodRequest(r) {
|
if utils.IsLibpodRequest(r) {
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func UnpauseContainer(w http.ResponseWriter, r *http.Request) {
|
func UnpauseContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
// /{version}/containers/(name)/unpause
|
// /{version}/containers/(name)/unpause
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/events"
|
"github.com/containers/podman/v3/libpod/events"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
|
@ -14,13 +15,12 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NOTE: this endpoint serves both the docker-compatible one and the new libpod
|
// GetEvents endpoint serves both the docker-compatible one and the new libpod one
|
||||||
// one.
|
|
||||||
func GetEvents(w http.ResponseWriter, r *http.Request) {
|
func GetEvents(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
fromStart bool
|
fromStart bool
|
||||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
json = jsoniter.ConfigCompatibleWithStandardLibrary // FIXME: this should happen on the package level
|
json = jsoniter.ConfigCompatibleWithStandardLibrary // FIXME: this should happen on the package level
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
"github.com/containers/podman/v3/pkg/api/server/idle"
|
"github.com/containers/podman/v3/pkg/api/server/idle"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/specgen/generate"
|
"github.com/containers/podman/v3/pkg/specgen/generate"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -19,7 +20,7 @@ import (
|
||||||
|
|
||||||
// ExecCreateHandler creates an exec session for a given container.
|
// ExecCreateHandler creates an exec session for a given container.
|
||||||
func ExecCreateHandler(w http.ResponseWriter, r *http.Request) {
|
func ExecCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
input := new(handlers.ExecCreateConfig)
|
input := new(handlers.ExecCreateConfig)
|
||||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
||||||
|
@ -101,7 +102,7 @@ func ExecCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// ExecInspectHandler inspects a given exec session.
|
// ExecInspectHandler inspects a given exec session.
|
||||||
func ExecInspectHandler(w http.ResponseWriter, r *http.Request) {
|
func ExecInspectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
sessionID := mux.Vars(r)["id"]
|
sessionID := mux.Vars(r)["id"]
|
||||||
sessionCtr, err := runtime.GetExecSessionContainer(sessionID)
|
sessionCtr, err := runtime.GetExecSessionContainer(sessionID)
|
||||||
|
@ -129,7 +130,7 @@ func ExecInspectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// ExecStartHandler runs a given exec session.
|
// ExecStartHandler runs a given exec session.
|
||||||
func ExecStartHandler(w http.ResponseWriter, r *http.Request) {
|
func ExecStartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
sessionID := mux.Vars(r)["id"]
|
sessionID := mux.Vars(r)["id"]
|
||||||
|
|
||||||
|
@ -191,7 +192,7 @@ func ExecStartHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if <-hijackChan {
|
if <-hijackChan {
|
||||||
// If connection was Hijacked, we have to signal it's being closed
|
// If connection was Hijacked, we have to signal it's being closed
|
||||||
t := r.Context().Value("idletracker").(*idle.Tracker)
|
t := r.Context().Value(api.IdleTrackerKey).(*idle.Tracker)
|
||||||
defer t.Close()
|
defer t.Close()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/auth"
|
"github.com/containers/podman/v3/pkg/auth"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
@ -45,7 +46,7 @@ func mergeNameAndTagOrDigest(name, tagOrDigest string) string {
|
||||||
func ExportImage(w http.ResponseWriter, r *http.Request) {
|
func ExportImage(w http.ResponseWriter, r *http.Request) {
|
||||||
// 200 ok
|
// 200 ok
|
||||||
// 500 server
|
// 500 server
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
tmpfile, err := ioutil.TempFile("", "api.tar")
|
tmpfile, err := ioutil.TempFile("", "api.tar")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -89,8 +90,8 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
destImage string
|
destImage string
|
||||||
)
|
)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Author string `schema:"author"`
|
Author string `schema:"author"`
|
||||||
|
@ -162,8 +163,8 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
|
||||||
// 200 no error
|
// 200 no error
|
||||||
// 404 repo does not exist or no read access
|
// 404 repo does not exist or no read access
|
||||||
// 500 internal
|
// 500 internal
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Changes []string `schema:"changes"`
|
Changes []string `schema:"changes"`
|
||||||
|
@ -234,8 +235,8 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
|
||||||
// 200 no error
|
// 200 no error
|
||||||
// 404 repo does not exist or no read access
|
// 404 repo does not exist or no read access
|
||||||
// 500 internal
|
// 500 internal
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
FromImage string `schema:"fromImage"`
|
FromImage string `schema:"fromImage"`
|
||||||
|
@ -301,7 +302,7 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
flush()
|
flush()
|
||||||
|
|
||||||
enc := json.NewEncoder(w)
|
enc := json.NewEncoder(w)
|
||||||
|
@ -407,8 +408,8 @@ func GetImages(w http.ResponseWriter, r *http.Request) {
|
||||||
func LoadImages(w http.ResponseWriter, r *http.Request) {
|
func LoadImages(w http.ResponseWriter, r *http.Request) {
|
||||||
// TODO this is basically wrong
|
// TODO this is basically wrong
|
||||||
// TODO ... improve these ^ messages to something useful
|
// TODO ... improve these ^ messages to something useful
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Changes map[string]string `json:"changes"` // Ignored
|
Changes map[string]string `json:"changes"` // Ignored
|
||||||
|
@ -465,8 +466,8 @@ func LoadImages(w http.ResponseWriter, r *http.Request) {
|
||||||
func ExportImages(w http.ResponseWriter, r *http.Request) {
|
func ExportImages(w http.ResponseWriter, r *http.Request) {
|
||||||
// 200 OK
|
// 200 OK
|
||||||
// 500 Error
|
// 500 Error
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Names []string `schema:"names"`
|
Names []string `schema:"names"`
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/auth"
|
"github.com/containers/podman/v3/pkg/auth"
|
||||||
"github.com/containers/podman/v3/pkg/channel"
|
"github.com/containers/podman/v3/pkg/channel"
|
||||||
"github.com/containers/storage/pkg/archive"
|
"github.com/containers/storage/pkg/archive"
|
||||||
|
@ -128,7 +129,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
Tag: []string{},
|
Tag: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||||
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
|
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
|
@ -410,7 +411,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
reporter := channel.NewWriter(make(chan []byte))
|
reporter := channel.NewWriter(make(chan []byte))
|
||||||
defer reporter.Close()
|
defer reporter.Close()
|
||||||
|
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
rtc, err := runtime.GetConfig()
|
rtc, err := runtime.GetConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||||
|
@ -520,7 +521,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Send headers and prime client for stream to come
|
// Send headers and prime client for stream to come
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
flush()
|
flush()
|
||||||
|
|
||||||
body := w.(io.Writer)
|
body := w.(io.Writer)
|
||||||
|
|
|
@ -6,11 +6,12 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HistoryImage(w http.ResponseWriter, r *http.Request) {
|
func HistoryImage(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
||||||
newImage, _, err := runtime.LibimageRuntime().LookupImage(name, nil)
|
newImage, _, err := runtime.LibimageRuntime().LookupImage(name, nil)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
@ -19,7 +20,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
filters []string
|
filters []string
|
||||||
)
|
)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
filterMap, err := util.PrepareFilters(r)
|
filterMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/auth"
|
"github.com/containers/podman/v3/pkg/auth"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
@ -22,8 +23,8 @@ import (
|
||||||
|
|
||||||
// PushImage is the handler for the compat http endpoint for pushing images.
|
// PushImage is the handler for the compat http endpoint for pushing images.
|
||||||
func PushImage(w http.ResponseWriter, r *http.Request) {
|
func PushImage(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
digestFile, err := ioutil.TempFile("", "digest.txt")
|
digestFile, err := ioutil.TempFile("", "digest.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -105,7 +106,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
flush()
|
flush()
|
||||||
|
|
||||||
var report jsonmessage.JSONMessage
|
var report jsonmessage.JSONMessage
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
|
@ -13,8 +14,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func RemoveImage(w http.ResponseWriter, r *http.Request) {
|
func RemoveImage(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Force bool `schema:"force"`
|
Force bool `schema:"force"`
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/auth"
|
"github.com/containers/podman/v3/pkg/auth"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
@ -16,8 +17,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func SearchImages(w http.ResponseWriter, r *http.Request) {
|
func SearchImages(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Term string `json:"term"`
|
Term string `json:"term"`
|
||||||
Limit int `json:"limit"`
|
Limit int `json:"limit"`
|
||||||
|
|
|
@ -6,11 +6,12 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TagImage(w http.ResponseWriter, r *http.Request) {
|
func TagImage(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
// /v1.xx/images/(name)/tag
|
// /v1.xx/images/(name)/tag
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/rootless"
|
"github.com/containers/podman/v3/pkg/rootless"
|
||||||
docker "github.com/docker/docker/api/types"
|
docker "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
|
@ -27,7 +28,7 @@ import (
|
||||||
func GetInfo(w http.ResponseWriter, r *http.Request) {
|
func GetInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
// 200 ok
|
// 200 ok
|
||||||
// 500 internal
|
// 500 internal
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
infoData, err := runtime.Info()
|
infoData, err := runtime.Info()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -14,11 +14,13 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/libpod/network"
|
"github.com/containers/podman/v3/libpod/network"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
networkid "github.com/containers/podman/v3/pkg/network"
|
networkid "github.com/containers/podman/v3/pkg/network"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
|
||||||
dockerNetwork "github.com/docker/docker/api/types/network"
|
dockerNetwork "github.com/docker/docker/api/types/network"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -32,7 +34,7 @@ type pluginInterface struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func InspectNetwork(w http.ResponseWriter, r *http.Request) {
|
func InspectNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
// scope is only used to see if the user passes any illegal value, verbose is not used but implemented
|
// scope is only used to see if the user passes any illegal value, verbose is not used but implemented
|
||||||
// for compatibility purposes only.
|
// for compatibility purposes only.
|
||||||
|
@ -42,7 +44,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
}{
|
}{
|
||||||
scope: "local",
|
scope: "local",
|
||||||
}
|
}
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
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()))
|
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
|
@ -195,7 +197,7 @@ func getPlugin(plugins []*libcni.NetworkConfig) (pluginInterface, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListNetworks(w http.ResponseWriter, r *http.Request) {
|
func ListNetworks(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
filterMap, err := util.PrepareFilters(r)
|
filterMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
|
@ -234,7 +236,7 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
name string
|
name string
|
||||||
networkCreate types.NetworkCreateRequest
|
networkCreate types.NetworkCreateRequest
|
||||||
)
|
)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
if err := json.NewDecoder(r.Body).Decode(&networkCreate); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&networkCreate); err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||||
return
|
return
|
||||||
|
@ -304,7 +306,7 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
|
func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
ic := abi.ContainerEngine{Libpod: runtime}
|
ic := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
|
@ -313,7 +315,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
// This is where you can override the golang default value for one of fields
|
// This is where you can override the golang default value for one of fields
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
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()))
|
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
|
@ -348,7 +350,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Connect adds a container to a network
|
// Connect adds a container to a network
|
||||||
func Connect(w http.ResponseWriter, r *http.Request) {
|
func Connect(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
aliases []string
|
aliases []string
|
||||||
|
@ -382,7 +384,7 @@ func Connect(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Disconnect removes a container from a network
|
// Disconnect removes a container from a network
|
||||||
func Disconnect(w http.ResponseWriter, r *http.Request) {
|
func Disconnect(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
var netDisconnect types.NetworkDisconnect
|
var netDisconnect types.NetworkDisconnect
|
||||||
if err := json.NewDecoder(r.Body).Decode(&netDisconnect); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&netDisconnect); err != nil {
|
||||||
|
@ -409,7 +411,7 @@ func Disconnect(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Prune removes unused networks
|
// Prune removes unused networks
|
||||||
func Prune(w http.ResponseWriter, r *http.Request) {
|
func Prune(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
filterMap, err := util.PrepareFilters(r)
|
filterMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
// Clients will use the Header availability to test which backend engine is in use.
|
// Clients will use the Header availability to test which backend engine is in use.
|
||||||
// Note: Additionally handler supports GET and HEAD methods
|
// Note: Additionally handler supports GET and HEAD methods
|
||||||
func Ping(w http.ResponseWriter, r *http.Request) {
|
func Ping(w http.ResponseWriter, r *http.Request) {
|
||||||
// Note API-Version and Libpod-API-Version are set in handler_api.go
|
// Note: API-Version and Libpod-API-Version are set in handler_api.go
|
||||||
w.Header().Set("BuildKit-Version", "")
|
w.Header().Set("BuildKit-Version", "")
|
||||||
w.Header().Set("Builder-Version", "")
|
w.Header().Set("Builder-Version", "")
|
||||||
w.Header().Set("Docker-Experimental", "true")
|
w.Header().Set("Docker-Experimental", "true")
|
||||||
|
|
|
@ -8,14 +8,15 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ResizeTTY(w http.ResponseWriter, r *http.Request) {
|
func ResizeTTY(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
|
|
||||||
// /containers/{id}/resize
|
// /containers/{id}/resize
|
||||||
query := struct {
|
query := struct {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
@ -17,7 +18,7 @@ import (
|
||||||
|
|
||||||
func ListSecrets(w http.ResponseWriter, r *http.Request) {
|
func ListSecrets(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
filtersMap, err := util.PrepareFilters(r)
|
filtersMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -53,7 +54,7 @@ func ListSecrets(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func InspectSecret(w http.ResponseWriter, r *http.Request) {
|
func InspectSecret(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
names := []string{name}
|
names := []string{name}
|
||||||
|
@ -86,7 +87,7 @@ func InspectSecret(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func RemoveSecret(w http.ResponseWriter, r *http.Request) {
|
func RemoveSecret(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
|
|
||||||
opts := entities.SecretRmOptions{}
|
opts := entities.SecretRmOptions{}
|
||||||
|
@ -106,7 +107,7 @@ func RemoveSecret(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func CreateSecret(w http.ResponseWriter, r *http.Request) {
|
func CreateSecret(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
opts := entities.SecretCreateOptions{}
|
opts := entities.SecretCreateOptions{}
|
||||||
createParams := struct {
|
createParams := struct {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
docker "github.com/docker/docker/api/types"
|
docker "github.com/docker/docker/api/types"
|
||||||
|
@ -14,7 +15,7 @@ import (
|
||||||
|
|
||||||
func GetDiskUsage(w http.ResponseWriter, r *http.Request) {
|
func GetDiskUsage(w http.ResponseWriter, r *http.Request) {
|
||||||
options := entities.SystemDfOptions{}
|
options := entities.SystemDfOptions{}
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
ic := abi.ContainerEngine{Libpod: runtime}
|
ic := abi.ContainerEngine{Libpod: runtime}
|
||||||
df, err := ic.SystemDf(r.Context(), options)
|
df, err := ic.SystemDf(r.Context(), options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities/types"
|
"github.com/containers/podman/v3/pkg/domain/entities/types"
|
||||||
"github.com/containers/podman/v3/version"
|
"github.com/containers/podman/v3/version"
|
||||||
|
@ -17,7 +18,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func VersionHandler(w http.ResponseWriter, r *http.Request) {
|
func VersionHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
running, err := define.GetVersion()
|
running, err := define.GetVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/filters"
|
"github.com/containers/podman/v3/pkg/domain/filters"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi/parse"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi/parse"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
@ -21,9 +22,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ListVolumes(w http.ResponseWriter, r *http.Request) {
|
func ListVolumes(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
|
||||||
)
|
|
||||||
filtersMap, err := util.PrepareFilters(r)
|
filtersMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
|
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
|
||||||
|
@ -79,8 +79,8 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) {
|
||||||
func CreateVolume(w http.ResponseWriter, r *http.Request) {
|
func CreateVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
volumeOptions []libpod.VolumeCreateOption
|
volumeOptions []libpod.VolumeCreateOption
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
)
|
)
|
||||||
/* No query string data*/
|
/* No query string data*/
|
||||||
query := struct{}{}
|
query := struct{}{}
|
||||||
|
@ -181,7 +181,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func InspectVolume(w http.ResponseWriter, r *http.Request) {
|
func InspectVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
vol, err := runtime.GetVolume(name)
|
vol, err := runtime.GetVolume(name)
|
||||||
|
@ -209,8 +209,8 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
)
|
)
|
||||||
query := struct {
|
query := struct {
|
||||||
Force bool `schema:"force"`
|
Force bool `schema:"force"`
|
||||||
|
@ -225,7 +225,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The implications for `force` differ between Docker and us, so we can't
|
/* The implications for `force` differ between Docker and us, so we can't
|
||||||
* simply pass the `force` parameter to `runeimt.RemoveVolume()`.
|
* simply pass the `force` parameter to `runtime.RemoveVolume()`.
|
||||||
* Specifically, Docker's behavior seems to be that `force` means "do not
|
* Specifically, Docker's behavior seems to be that `force` means "do not
|
||||||
* error on missing volume"; ours means "remove any not-running containers
|
* error on missing volume"; ours means "remove any not-running containers
|
||||||
* using the volume at the same time".
|
* using the volume at the same time".
|
||||||
|
@ -263,7 +263,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func PruneVolumes(w http.ResponseWriter, r *http.Request) {
|
func PruneVolumes(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
filterMap, err := util.PrepareFilters(r)
|
filterMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/compat"
|
"github.com/containers/podman/v3/pkg/api/handlers/compat"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
@ -18,8 +19,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ContainerExists(w http.ResponseWriter, r *http.Request) {
|
func ContainerExists(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
// Now use the ABI implementation to prevent us from having duplicate
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
// code.
|
// code.
|
||||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
@ -58,7 +59,7 @@ func ContainerExists(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListContainers(w http.ResponseWriter, r *http.Request) {
|
func ListContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
External bool `schema:"external"`
|
External bool `schema:"external"`
|
||||||
|
@ -89,7 +90,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
limit = query.Last
|
limit = query.Last
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
// Now use the ABI implementation to prevent us from having duplicate
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
// code.
|
// code.
|
||||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
@ -118,7 +119,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetContainer(w http.ResponseWriter, r *http.Request) {
|
func GetContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Size bool `schema:"size"`
|
Size bool `schema:"size"`
|
||||||
}{
|
}{
|
||||||
|
@ -130,7 +131,7 @@ func GetContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
container, err := runtime.LookupContainer(name)
|
container, err := runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -150,7 +151,7 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnmountContainer(w http.ResponseWriter, r *http.Request) {
|
func UnmountContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
conn, err := runtime.LookupContainer(name)
|
conn, err := runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -165,7 +166,7 @@ func UnmountContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
utils.WriteResponse(w, http.StatusNoContent, "")
|
utils.WriteResponse(w, http.StatusNoContent, "")
|
||||||
}
|
}
|
||||||
func MountContainer(w http.ResponseWriter, r *http.Request) {
|
func MountContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
conn, err := runtime.LookupContainer(name)
|
conn, err := runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -181,7 +182,7 @@ func MountContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func ShowMountedContainers(w http.ResponseWriter, r *http.Request) {
|
func ShowMountedContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
response := make(map[string]string)
|
response := make(map[string]string)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
conns, err := runtime.GetAllContainers()
|
conns, err := runtime.GetAllContainers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
|
@ -201,7 +202,7 @@ func ShowMountedContainers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func Checkpoint(w http.ResponseWriter, r *http.Request) {
|
func Checkpoint(w http.ResponseWriter, r *http.Request) {
|
||||||
var targetFile string
|
var targetFile string
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Keep bool `schema:"keep"`
|
Keep bool `schema:"keep"`
|
||||||
LeaveRunning bool `schema:"leaveRunning"`
|
LeaveRunning bool `schema:"leaveRunning"`
|
||||||
|
@ -218,7 +219,7 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
ctr, err := runtime.LookupContainer(name)
|
ctr, err := runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.ContainerNotFound(w, name, err)
|
utils.ContainerNotFound(w, name, err)
|
||||||
|
@ -268,7 +269,7 @@ func Restore(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
targetFile string
|
targetFile string
|
||||||
)
|
)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Keep bool `schema:"keep"`
|
Keep bool `schema:"keep"`
|
||||||
TCPEstablished bool `schema:"tcpEstablished"`
|
TCPEstablished bool `schema:"tcpEstablished"`
|
||||||
|
@ -287,7 +288,7 @@ func Restore(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
ctr, err := runtime.LookupContainer(name)
|
ctr, err := runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.ContainerNotFound(w, name, err)
|
utils.ContainerNotFound(w, name, err)
|
||||||
|
@ -328,7 +329,7 @@ func Restore(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func InitContainer(w http.ResponseWriter, r *http.Request) {
|
func InitContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
ctr, err := runtime.LookupContainer(name)
|
ctr, err := runtime.LookupContainer(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.ContainerNotFound(w, name, err)
|
utils.ContainerNotFound(w, name, err)
|
||||||
|
@ -347,7 +348,7 @@ func InitContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShouldRestart(w http.ResponseWriter, r *http.Request) {
|
func ShouldRestart(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
// Now use the ABI implementation to prevent us from having duplicate
|
// Now use the ABI implementation to prevent us from having duplicate
|
||||||
// code.
|
// code.
|
||||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/specgen"
|
"github.com/containers/podman/v3/pkg/specgen"
|
||||||
"github.com/containers/podman/v3/pkg/specgen/generate"
|
"github.com/containers/podman/v3/pkg/specgen/generate"
|
||||||
|
@ -16,7 +17,7 @@ import (
|
||||||
// CreateContainer takes a specgenerator and makes a container. It returns
|
// CreateContainer takes a specgenerator and makes a container. It returns
|
||||||
// the new container ID on success along with any warnings.
|
// the new container ID on success along with any warnings.
|
||||||
func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
var sg specgen.SpecGenerator
|
var sg specgen.SpecGenerator
|
||||||
if err := json.NewDecoder(r.Body).Decode(&sg); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&sg); err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/cgroups"
|
"github.com/containers/podman/v3/pkg/cgroups"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
@ -16,8 +17,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func StatsContainer(w http.ResponseWriter, r *http.Request) {
|
func StatsContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
|
|
||||||
// Check if service is running rootless (cheap check)
|
// Check if service is running rootless (cheap check)
|
||||||
if rootless.IsRootless() {
|
if rootless.IsRootless() {
|
||||||
|
@ -60,7 +61,7 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Write header and content type.
|
// Write header and content type.
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
if flusher, ok := w.(http.Flusher); ok {
|
if flusher, ok := w.(http.Flusher); ok {
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
@ -13,8 +14,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
|
func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Name bool `schema:"useName"`
|
Name bool `schema:"useName"`
|
||||||
New bool `schema:"new"`
|
New bool `schema:"new"`
|
||||||
|
@ -59,8 +60,8 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateKube(w http.ResponseWriter, r *http.Request) {
|
func GenerateKube(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Names []string `schema:"names"`
|
Names []string `schema:"names"`
|
||||||
Service bool `schema:"service"`
|
Service bool `schema:"service"`
|
||||||
|
|
|
@ -6,10 +6,11 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RunHealthCheck(w http.ResponseWriter, r *http.Request) {
|
func RunHealthCheck(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
status, err := runtime.HealthCheck(name)
|
status, err := runtime.HealthCheck(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/auth"
|
"github.com/containers/podman/v3/pkg/auth"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
@ -41,7 +42,7 @@ import (
|
||||||
// create
|
// create
|
||||||
|
|
||||||
func ImageExists(w http.ResponseWriter, r *http.Request) {
|
func ImageExists(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
||||||
ir := abi.ImageEngine{Libpod: runtime}
|
ir := abi.ImageEngine{Libpod: runtime}
|
||||||
|
@ -58,9 +59,9 @@ func ImageExists(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImageTree(w http.ResponseWriter, r *http.Request) {
|
func ImageTree(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
WhatRequires bool `schema:"whatrequires"`
|
WhatRequires bool `schema:"whatrequires"`
|
||||||
}{
|
}{
|
||||||
|
@ -101,8 +102,8 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetImages(w http.ResponseWriter, r *http.Request) {
|
func GetImages(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool
|
All bool
|
||||||
Digests bool
|
Digests bool
|
||||||
|
@ -146,8 +147,8 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
}{
|
}{
|
||||||
|
@ -198,8 +199,8 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
output string
|
output string
|
||||||
)
|
)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Compress bool `schema:"compress"`
|
Compress bool `schema:"compress"`
|
||||||
Format string `schema:"format"`
|
Format string `schema:"format"`
|
||||||
|
@ -279,8 +280,8 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
output string
|
output string
|
||||||
)
|
)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Compress bool `schema:"compress"`
|
Compress bool `schema:"compress"`
|
||||||
Format string `schema:"format"`
|
Format string `schema:"format"`
|
||||||
|
@ -369,7 +370,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImagesLoad(w http.ResponseWriter, r *http.Request) {
|
func ImagesLoad(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
tmpfile, err := ioutil.TempFile("", "libpod-images-load.tar")
|
tmpfile, err := ioutil.TempFile("", "libpod-images-load.tar")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -398,8 +399,8 @@ func ImagesLoad(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImagesImport(w http.ResponseWriter, r *http.Request) {
|
func ImagesImport(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Changes []string `schema:"changes"`
|
Changes []string `schema:"changes"`
|
||||||
Message string `schema:"message"`
|
Message string `schema:"message"`
|
||||||
|
@ -453,8 +454,8 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// PushImage is the handler for the compat http endpoint for pushing images.
|
// PushImage is the handler for the compat http endpoint for pushing images.
|
||||||
func PushImage(w http.ResponseWriter, r *http.Request) {
|
func PushImage(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Destination string `schema:"destination"`
|
Destination string `schema:"destination"`
|
||||||
|
@ -522,8 +523,8 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
destImage string
|
destImage string
|
||||||
mimeType string
|
mimeType string
|
||||||
)
|
)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Author string `schema:"author"`
|
Author string `schema:"author"`
|
||||||
|
@ -597,7 +598,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func UntagImage(w http.ResponseWriter, r *http.Request) {
|
func UntagImage(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
tags := []string{} // Note: if empty, all tags will be removed from the image.
|
tags := []string{} // Note: if empty, all tags will be removed from the image.
|
||||||
repo := r.Form.Get("repo")
|
repo := r.Form.Get("repo")
|
||||||
|
@ -641,8 +642,8 @@ func UntagImage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// ImagesBatchRemove is the endpoint for batch image removal.
|
// ImagesBatchRemove is the endpoint for batch image removal.
|
||||||
func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
|
func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
Force bool `schema:"force"`
|
Force bool `schema:"force"`
|
||||||
|
@ -665,8 +666,8 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// ImagesRemove is the endpoint for removing one image.
|
// ImagesRemove is the endpoint for removing one image.
|
||||||
func ImagesRemove(w http.ResponseWriter, r *http.Request) {
|
func ImagesRemove(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Force bool `schema:"force"`
|
Force bool `schema:"force"`
|
||||||
}{
|
}{
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/auth"
|
"github.com/containers/podman/v3/pkg/auth"
|
||||||
"github.com/containers/podman/v3/pkg/channel"
|
"github.com/containers/podman/v3/pkg/channel"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
|
@ -23,8 +24,8 @@ import (
|
||||||
// transport or be normalized to one). Other transports are rejected as they
|
// transport or be normalized to one). Other transports are rejected as they
|
||||||
// do not make sense in a remote context.
|
// do not make sense in a remote context.
|
||||||
func ImagesPull(w http.ResponseWriter, r *http.Request) {
|
func ImagesPull(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Reference string `schema:"reference"`
|
Reference string `schema:"reference"`
|
||||||
OS string `schema:"OS"`
|
OS string `schema:"OS"`
|
||||||
|
@ -107,7 +108,7 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
flush()
|
flush()
|
||||||
|
|
||||||
enc := json.NewEncoder(w)
|
enc := json.NewEncoder(w)
|
||||||
|
|
|
@ -5,11 +5,12 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetInfo(w http.ResponseWriter, r *http.Request) {
|
func GetInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
info, err := containerEngine.Info(r.Context())
|
info, err := containerEngine.Info(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/auth"
|
"github.com/containers/podman/v3/pkg/auth"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
@ -20,8 +21,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ManifestCreate(w http.ResponseWriter, r *http.Request) {
|
func ManifestCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Name []string `schema:"name"`
|
Name []string `schema:"name"`
|
||||||
Image []string `schema:"image"`
|
Image []string `schema:"image"`
|
||||||
|
@ -57,7 +58,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// ExistsManifest check if a manifest list exists
|
// ExistsManifest check if a manifest list exists
|
||||||
func ExistsManifest(w http.ResponseWriter, r *http.Request) {
|
func ExistsManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
||||||
imageEngine := abi.ImageEngine{Libpod: runtime}
|
imageEngine := abi.ImageEngine{Libpod: runtime}
|
||||||
|
@ -74,7 +75,7 @@ func ExistsManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ManifestInspect(w http.ResponseWriter, r *http.Request) {
|
func ManifestInspect(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
||||||
imageEngine := abi.ImageEngine{Libpod: runtime}
|
imageEngine := abi.ImageEngine{Libpod: runtime}
|
||||||
|
@ -94,7 +95,7 @@ func ManifestInspect(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ManifestAdd(w http.ResponseWriter, r *http.Request) {
|
func ManifestAdd(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
var addOptions entities.ManifestAddOptions
|
var addOptions entities.ManifestAddOptions
|
||||||
if err := json.NewDecoder(r.Body).Decode(&addOptions); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&addOptions); err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||||
|
@ -124,8 +125,8 @@ func ManifestAdd(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ManifestRemove(w http.ResponseWriter, r *http.Request) {
|
func ManifestRemove(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Digest string `schema:"digest"`
|
Digest string `schema:"digest"`
|
||||||
}{
|
}{
|
||||||
|
@ -155,8 +156,8 @@ func ManifestRemove(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ManifestPush(w http.ResponseWriter, r *http.Request) {
|
func ManifestPush(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
Destination string `schema:"destination"`
|
Destination string `schema:"destination"`
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/libpod/network"
|
"github.com/containers/podman/v3/libpod/network"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
@ -16,8 +17,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateNetwork(w http.ResponseWriter, r *http.Request) {
|
func CreateNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
options := entities.NetworkCreateOptions{}
|
options := entities.NetworkCreateOptions{}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&options); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&options); err != nil {
|
||||||
utils.Error(w, "unable to marshall input", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
utils.Error(w, "unable to marshall input", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||||
|
@ -45,7 +46,7 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
utils.WriteResponse(w, http.StatusOK, report)
|
utils.WriteResponse(w, http.StatusOK, report)
|
||||||
}
|
}
|
||||||
func ListNetworks(w http.ResponseWriter, r *http.Request) {
|
func ListNetworks(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
filterMap, err := util.PrepareFilters(r)
|
filterMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
|
utils.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError,
|
||||||
|
@ -66,8 +67,8 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
|
func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Force bool `schema:"force"`
|
Force bool `schema:"force"`
|
||||||
}{
|
}{
|
||||||
|
@ -100,8 +101,8 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func InspectNetwork(w http.ResponseWriter, r *http.Request) {
|
func InspectNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
}{
|
}{
|
||||||
// override any golang type defaults
|
// override any golang type defaults
|
||||||
|
@ -129,7 +130,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Connect adds a container to a network
|
// Connect adds a container to a network
|
||||||
func Connect(w http.ResponseWriter, r *http.Request) {
|
func Connect(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
var netConnect entities.NetworkConnectOptions
|
var netConnect entities.NetworkConnectOptions
|
||||||
if err := json.NewDecoder(r.Body).Decode(&netConnect); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&netConnect); err != nil {
|
||||||
|
@ -155,7 +156,7 @@ func Connect(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// ExistsNetwork check if a network exists
|
// ExistsNetwork check if a network exists
|
||||||
func ExistsNetwork(w http.ResponseWriter, r *http.Request) {
|
func ExistsNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
||||||
ic := abi.ContainerEngine{Libpod: runtime}
|
ic := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
@ -173,7 +174,7 @@ func ExistsNetwork(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Prune removes unused networks
|
// Prune removes unused networks
|
||||||
func Prune(w http.ResponseWriter, r *http.Request) {
|
func Prune(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
filterMap, err := util.PrepareFilters(r)
|
filterMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/auth"
|
"github.com/containers/podman/v3/pkg/auth"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
@ -19,8 +20,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func PlayKube(w http.ResponseWriter, r *http.Request) {
|
func PlayKube(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := struct {
|
query := struct {
|
||||||
Network string `schema:"network"`
|
Network string `schema:"network"`
|
||||||
TLSVerify bool `schema:"tlsVerify"`
|
TLSVerify bool `schema:"tlsVerify"`
|
||||||
|
@ -121,7 +122,7 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PlayKubeDown(w http.ResponseWriter, r *http.Request) {
|
func PlayKubeDown(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
|
tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/podman/v3/pkg/specgen"
|
"github.com/containers/podman/v3/pkg/specgen"
|
||||||
|
@ -27,7 +28,7 @@ import (
|
||||||
|
|
||||||
func PodCreate(w http.ResponseWriter, r *http.Request) {
|
func PodCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
psg := specgen.PodSpecGenerator{InfraContainerSpec: &specgen.SpecGenerator{}}
|
psg := specgen.PodSpecGenerator{InfraContainerSpec: &specgen.SpecGenerator{}}
|
||||||
|
@ -100,7 +101,7 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Pods(w http.ResponseWriter, r *http.Request) {
|
func Pods(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
filterMap, err := util.PrepareFilters(r)
|
filterMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -122,7 +123,7 @@ func Pods(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PodInspect(w http.ResponseWriter, r *http.Request) {
|
func PodInspect(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
pod, err := runtime.LookupPod(name)
|
pod, err := runtime.LookupPod(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -144,8 +145,8 @@ func PodInspect(w http.ResponseWriter, r *http.Request) {
|
||||||
func PodStop(w http.ResponseWriter, r *http.Request) {
|
func PodStop(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
stopError error
|
stopError error
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
responses map[string]error
|
responses map[string]error
|
||||||
)
|
)
|
||||||
query := struct {
|
query := struct {
|
||||||
|
@ -206,7 +207,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PodStart(w http.ResponseWriter, r *http.Request) {
|
func PodStart(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
pod, err := runtime.LookupPod(name)
|
pod, err := runtime.LookupPod(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -243,8 +244,8 @@ func PodStart(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func PodDelete(w http.ResponseWriter, r *http.Request) {
|
func PodDelete(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
)
|
)
|
||||||
query := struct {
|
query := struct {
|
||||||
Force bool `schema:"force"`
|
Force bool `schema:"force"`
|
||||||
|
@ -272,7 +273,7 @@ func PodDelete(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PodRestart(w http.ResponseWriter, r *http.Request) {
|
func PodRestart(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
pod, err := runtime.LookupPod(name)
|
pod, err := runtime.LookupPod(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -308,7 +309,7 @@ func PodPrune(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func PodPruneHelper(r *http.Request) ([]*entities.PodPruneReport, error) {
|
func PodPruneHelper(r *http.Request) ([]*entities.PodPruneReport, error) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
responses, err := runtime.PrunePods(r.Context())
|
responses, err := runtime.PrunePods(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -325,7 +326,7 @@ func PodPruneHelper(r *http.Request) ([]*entities.PodPruneReport, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PodPause(w http.ResponseWriter, r *http.Request) {
|
func PodPause(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
pod, err := runtime.LookupPod(name)
|
pod, err := runtime.LookupPod(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -351,7 +352,7 @@ func PodPause(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PodUnpause(w http.ResponseWriter, r *http.Request) {
|
func PodUnpause(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
pod, err := runtime.LookupPod(name)
|
pod, err := runtime.LookupPod(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -377,8 +378,8 @@ func PodUnpause(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PodTop(w http.ResponseWriter, r *http.Request) {
|
func PodTop(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
PsArgs string `schema:"ps_args"`
|
PsArgs string `schema:"ps_args"`
|
||||||
|
@ -420,8 +421,8 @@ func PodTop(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func PodKill(w http.ResponseWriter, r *http.Request) {
|
func PodKill(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
signal = "SIGKILL"
|
signal = "SIGKILL"
|
||||||
)
|
)
|
||||||
query := struct {
|
query := struct {
|
||||||
|
@ -489,7 +490,7 @@ func PodKill(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PodExists(w http.ResponseWriter, r *http.Request) {
|
func PodExists(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
_, err := runtime.LookupPod(name)
|
_, err := runtime.LookupPod(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -500,8 +501,8 @@ func PodExists(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PodStats(w http.ResponseWriter, r *http.Request) {
|
func PodStats(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
NamesOrIDs []string `schema:"namesOrIDs"`
|
NamesOrIDs []string `schema:"namesOrIDs"`
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
|
@ -15,8 +16,8 @@ import (
|
||||||
|
|
||||||
func CreateSecret(w http.ResponseWriter, r *http.Request) {
|
func CreateSecret(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
)
|
)
|
||||||
|
|
||||||
decoder.RegisterConverter(map[string]string{}, func(str string) reflect.Value {
|
decoder.RegisterConverter(map[string]string{}, func(str string) reflect.Value {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
|
@ -14,8 +15,8 @@ import (
|
||||||
|
|
||||||
// SystemPrune removes unused data
|
// SystemPrune removes unused data
|
||||||
func SystemPrune(w http.ResponseWriter, r *http.Request) {
|
func SystemPrune(w http.ResponseWriter, r *http.Request) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
|
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
|
@ -53,7 +54,7 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) {
|
||||||
func DiskUsage(w http.ResponseWriter, r *http.Request) {
|
func DiskUsage(w http.ResponseWriter, r *http.Request) {
|
||||||
// Options are only used by the CLI
|
// Options are only used by the CLI
|
||||||
options := entities.SystemDfOptions{}
|
options := entities.SystemDfOptions{}
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
ic := abi.ContainerEngine{Libpod: runtime}
|
ic := abi.ContainerEngine{Libpod: runtime}
|
||||||
response, err := ic.SystemDf(r.Context(), options)
|
response, err := ic.SystemDf(r.Context(), options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities/reports"
|
"github.com/containers/podman/v3/pkg/domain/entities/reports"
|
||||||
"github.com/containers/podman/v3/pkg/domain/filters"
|
"github.com/containers/podman/v3/pkg/domain/filters"
|
||||||
|
@ -21,8 +22,8 @@ import (
|
||||||
func CreateVolume(w http.ResponseWriter, r *http.Request) {
|
func CreateVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
volumeOptions []libpod.VolumeCreateOption
|
volumeOptions []libpod.VolumeCreateOption
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
)
|
)
|
||||||
query := struct {
|
query := struct {
|
||||||
}{
|
}{
|
||||||
|
@ -75,7 +76,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func InspectVolume(w http.ResponseWriter, r *http.Request) {
|
func InspectVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
vol, err := runtime.GetVolume(name)
|
vol, err := runtime.GetVolume(name)
|
||||||
|
@ -96,7 +97,7 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func ListVolumes(w http.ResponseWriter, r *http.Request) {
|
func ListVolumes(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
filterMap, err := util.PrepareFilters(r)
|
filterMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -142,7 +143,7 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) {
|
func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
)
|
)
|
||||||
filterMap, err := util.PrepareFilters(r)
|
filterMap, err := util.PrepareFilters(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -164,8 +165,8 @@ func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) {
|
||||||
|
|
||||||
func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
decoder = r.Context().Value("decoder").(*schema.Decoder)
|
decoder = r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
)
|
)
|
||||||
query := struct {
|
query := struct {
|
||||||
Force bool `schema:"force"`
|
Force bool `schema:"force"`
|
||||||
|
@ -197,7 +198,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// ExistsVolume check if a volume exists
|
// ExistsVolume check if a volume exists
|
||||||
func ExistsVolume(w http.ResponseWriter, r *http.Request) {
|
func ExistsVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
|
|
||||||
ic := abi.ContainerEngine{Libpod: runtime}
|
ic := abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containers/podman/v3/libpod/events"
|
"github.com/containers/podman/v3/libpod/events"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
"github.com/containers/podman/v3/pkg/domain/infra/abi"
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ func WaitContainerDocker(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
query := waitQueryDocker{}
|
query := waitQueryDocker{}
|
||||||
|
|
||||||
decoder := ctx.Value("decoder").(*schema.Decoder)
|
decoder := ctx.Value(api.DecoderKey).(*schema.Decoder)
|
||||||
if err = decoder.Decode(&query, r.URL.Query()); err != nil {
|
if err = decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||||
Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
|
@ -68,7 +69,7 @@ func WaitContainerDocker(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// In docker compatibility mode we have to send headers in advance,
|
// In docker compatibility mode we have to send headers in advance,
|
||||||
// otherwise docker client would freeze.
|
// otherwise docker client would freeze.
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
if flusher, ok := w.(http.Flusher); ok {
|
if flusher, ok := w.(http.Flusher); ok {
|
||||||
flusher.Flush()
|
flusher.Flush()
|
||||||
|
@ -103,7 +104,7 @@ func WaitContainerLibpod(w http.ResponseWriter, r *http.Request) {
|
||||||
interval = time.Millisecond * 250
|
interval = time.Millisecond * 250
|
||||||
conditions = []define.ContainerStatus{define.ContainerStateStopped, define.ContainerStateExited}
|
conditions = []define.ContainerStatus{define.ContainerStateStopped, define.ContainerStateExited}
|
||||||
)
|
)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
query := waitQueryLibpod{}
|
query := waitQueryLibpod{}
|
||||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||||
Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
|
@ -143,7 +144,7 @@ func WaitContainerLibpod(w http.ResponseWriter, r *http.Request) {
|
||||||
type containerWaitFn func(conditions ...define.ContainerStatus) (int32, error)
|
type containerWaitFn func(conditions ...define.ContainerStatus) (int32, error)
|
||||||
|
|
||||||
func createContainerWaitFn(ctx context.Context, containerName string, interval time.Duration) containerWaitFn {
|
func createContainerWaitFn(ctx context.Context, containerName string, interval time.Duration) containerWaitFn {
|
||||||
runtime := ctx.Value("runtime").(*libpod.Runtime)
|
runtime := ctx.Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
var containerEngine entities.ContainerEngine = &abi.ContainerEngine{Libpod: runtime}
|
var containerEngine entities.ContainerEngine = &abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
||||||
return func(conditions ...define.ContainerStatus) (int32, error) {
|
return func(conditions ...define.ContainerStatus) (int32, error) {
|
||||||
|
@ -205,7 +206,7 @@ func waitRemoved(ctrWait containerWaitFn) (int32, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitNextExit(ctx context.Context, containerName string) (int32, error) {
|
func waitNextExit(ctx context.Context, containerName string) (int32, error) {
|
||||||
runtime := ctx.Value("runtime").(*libpod.Runtime)
|
runtime := ctx.Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
containerEngine := &abi.ContainerEngine{Libpod: runtime}
|
containerEngine := &abi.ContainerEngine{Libpod: runtime}
|
||||||
eventChannel := make(chan *events.Event)
|
eventChannel := make(chan *events.Event)
|
||||||
errChannel := make(chan error)
|
errChannel := make(chan error)
|
||||||
|
@ -237,7 +238,7 @@ func waitNotRunning(ctrWait containerWaitFn) (int32, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func containerExists(ctx context.Context, name string) (bool, error) {
|
func containerExists(ctx context.Context, name string) (bool, error) {
|
||||||
runtime := ctx.Value("runtime").(*libpod.Runtime)
|
runtime := ctx.Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
var containerEngine entities.ContainerEngine = &abi.ContainerEngine{Libpod: runtime}
|
var containerEngine entities.ContainerEngine = &abi.ContainerEngine{Libpod: runtime}
|
||||||
|
|
||||||
var ctrExistsOpts entities.ContainerExistsOptions
|
var ctrExistsOpts entities.ContainerExistsOptions
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/containers/image/v5/transports/alltransports"
|
"github.com/containers/image/v5/transports/alltransports"
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/podman/v3/libpod"
|
"github.com/containers/podman/v3/libpod"
|
||||||
|
api "github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
@ -51,8 +52,8 @@ func ParseStorageReference(name string) (types.ImageReference, error) {
|
||||||
// GetImages is a common function used to get images for libpod and other compatibility
|
// GetImages is a common function used to get images for libpod and other compatibility
|
||||||
// mechanisms
|
// mechanisms
|
||||||
func GetImages(w http.ResponseWriter, r *http.Request) ([]*libimage.Image, error) {
|
func GetImages(w http.ResponseWriter, r *http.Request) ([]*libimage.Image, error) {
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
query := struct {
|
query := struct {
|
||||||
All bool
|
All bool
|
||||||
Digests bool
|
Digests bool
|
||||||
|
@ -87,7 +88,7 @@ func GetImages(w http.ResponseWriter, r *http.Request) ([]*libimage.Image, error
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetImage(r *http.Request, name string) (*libimage.Image, error) {
|
func GetImage(r *http.Request, name string) (*libimage.Image, error) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||||
image, _, err := runtime.LibimageRuntime().LookupImage(name, nil)
|
image, _, err := runtime.LibimageRuntime().LookupImage(name, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -1,61 +1,25 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
|
||||||
"github.com/containers/podman/v3/pkg/auth"
|
|
||||||
"github.com/containers/podman/v3/version"
|
"github.com/containers/podman/v3/version"
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// APIHandler is a wrapper to enhance HandlerFunc's and remove redundant code
|
// APIHandler is a wrapper to enhance HandlerFunc's and remove redundant code
|
||||||
func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
|
func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
// http.Server hides panics, we want to see them and fix the cause.
|
|
||||||
defer func() {
|
|
||||||
err := recover()
|
|
||||||
if err != nil {
|
|
||||||
buf := make([]byte, 1<<20)
|
|
||||||
n := runtime.Stack(buf, true)
|
|
||||||
logrus.Warnf("Recovering from API handler panic: %v, %s", err, buf[:n])
|
|
||||||
// Try to inform client things went south... won't work if handler already started writing response body
|
|
||||||
utils.InternalServerError(w, fmt.Errorf("%v", err))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Wrapper to hide some boilerplate
|
// Wrapper to hide some boilerplate
|
||||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
rid := uuid.New().String()
|
|
||||||
logrus.Infof("APIHandler(%s) -- %s %s BEGIN", rid, r.Method, r.URL.String())
|
|
||||||
if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
|
||||||
for k, v := range r.Header {
|
|
||||||
switch auth.HeaderAuthName(k) {
|
|
||||||
case auth.XRegistryConfigHeader, auth.XRegistryAuthHeader:
|
|
||||||
logrus.Debugf("APIHandler(%s) -- Header: %s=<hidden>", rid, k)
|
|
||||||
default:
|
|
||||||
logrus.Debugf("APIHandler(%s) -- Header: %s=%v", rid, k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Set in case handler wishes to correlate logging events
|
|
||||||
r.Header.Set("X-Reference-Id", rid)
|
|
||||||
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
logrus.Infof("Failed Request: unable to parse form: %q (%s)", err, rid)
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"X-Reference-Id": r.Header.Get("X-Reference-Id"),
|
||||||
|
}).Info("Failed Request: unable to parse form: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use r.ConnContext when ported to go 1.13
|
|
||||||
c := context.WithValue(r.Context(), "decoder", s.Decoder) // nolint
|
|
||||||
c = context.WithValue(c, "runtime", s.Runtime) // nolint
|
|
||||||
c = context.WithValue(c, "shutdownFunc", s.Shutdown) // nolint
|
|
||||||
c = context.WithValue(c, "idletracker", s.idleTracker) // nolint
|
|
||||||
r = r.WithContext(c)
|
|
||||||
|
|
||||||
cv := version.APIVersion[version.Compat][version.CurrentAPI]
|
cv := version.APIVersion[version.Compat][version.CurrentAPI]
|
||||||
w.Header().Set("API-Version", fmt.Sprintf("%d.%d", cv.Major, cv.Minor))
|
w.Header().Set("API-Version", fmt.Sprintf("%d.%d", cv.Major, cv.Minor))
|
||||||
|
|
||||||
|
@ -70,7 +34,6 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
h(w, r)
|
h(w, r)
|
||||||
logrus.Debugf("APIHandler(%s) -- %s %s END", rid, r.Method, r.URL.String())
|
|
||||||
}
|
}
|
||||||
fn(w, r)
|
fn(w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type responseWriter struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiLogger = &logrus.Logger{
|
||||||
|
Formatter: &logrus.TextFormatter{
|
||||||
|
DisableColors: true,
|
||||||
|
DisableLevelTruncation: true,
|
||||||
|
FullTimestamp: true,
|
||||||
|
QuoteEmptyFields: true,
|
||||||
|
TimestampFormat: time.RFC3339,
|
||||||
|
},
|
||||||
|
Level: logrus.TraceLevel,
|
||||||
|
Out: logrus.StandardLogger().Out,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l responseWriter) Write(b []byte) (int, error) {
|
||||||
|
apiLogger.WithFields(logrus.Fields{
|
||||||
|
"API": "response",
|
||||||
|
"X-Reference-Id": l.Header().Get("X-Reference-Id"),
|
||||||
|
}).Trace(string(b))
|
||||||
|
return l.ResponseWriter.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loggingHandler() mux.MiddlewareFunc {
|
||||||
|
return func(h http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
annotated := apiLogger.WithFields(logrus.Fields{
|
||||||
|
"API": "request",
|
||||||
|
"X-Reference-Id": r.Header.Get("X-Reference-Id"),
|
||||||
|
})
|
||||||
|
r.Body = ioutil.NopCloser(
|
||||||
|
io.TeeReader(r.Body, annotated.WriterLevel(logrus.TraceLevel)))
|
||||||
|
|
||||||
|
w = responseWriter{ResponseWriter: w}
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/containers/podman/v3/pkg/api/handlers/utils"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// panicHandler captures panics from endpoint handlers and logs stack trace
|
||||||
|
func panicHandler() mux.MiddlewareFunc {
|
||||||
|
return func(h http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// http.Server hides panics from handlers, we want to record them and fix the cause
|
||||||
|
defer func() {
|
||||||
|
err := recover()
|
||||||
|
if err != nil {
|
||||||
|
buf := make([]byte, 1<<20)
|
||||||
|
n := runtime.Stack(buf, true)
|
||||||
|
logrus.Warnf("Recovering from API service endpoint handler panic: %v, %s", err, buf[:n])
|
||||||
|
// Try to inform client things went south... won't work if handler already started writing response body
|
||||||
|
utils.InternalServerError(w, fmt.Errorf("%v", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/containers/podman/v3/pkg/api/types"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/gorilla/handlers"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// referenceIDHandler adds X-Reference-Id Header allowing event correlation
|
||||||
|
// and Apache style request logging
|
||||||
|
func referenceIDHandler() mux.MiddlewareFunc {
|
||||||
|
return func(h http.Handler) http.Handler {
|
||||||
|
return handlers.CombinedLoggingHandler(logrus.StandardLogger().Out,
|
||||||
|
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
rid := r.Header.Get("X-Reference-Id")
|
||||||
|
if rid == "" {
|
||||||
|
if c := r.Context().Value(types.ConnKey); c == nil {
|
||||||
|
rid = uuid.New().String()
|
||||||
|
} else {
|
||||||
|
rid = fmt.Sprintf("%p", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Header.Set("X-Reference-Id", rid)
|
||||||
|
w.Header().Set("X-Reference-Id", rid)
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package idle
|
package idle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -39,7 +40,10 @@ func (t *Tracker) ConnState(conn net.Conn, state http.ConnState) {
|
||||||
t.mux.Lock()
|
t.mux.Lock()
|
||||||
defer t.mux.Unlock()
|
defer t.mux.Unlock()
|
||||||
|
|
||||||
logrus.Debugf("IdleTracker %p:%v %dm+%dh/%dt connection(s)", conn, state, len(t.managed), t.hijacked, t.TotalConnections())
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"X-Reference-Id": fmt.Sprintf("%p", conn),
|
||||||
|
}).Debugf("IdleTracker:%v %dm+%dh/%dt connection(s)", state, len(t.managed), t.hijacked, t.TotalConnections())
|
||||||
|
|
||||||
switch state {
|
switch state {
|
||||||
case http.StateNew:
|
case http.StateNew:
|
||||||
t.total++
|
t.total++
|
||||||
|
@ -68,7 +72,9 @@ func (t *Tracker) ConnState(conn net.Conn, state http.ConnState) {
|
||||||
if _, found := t.managed[conn]; found {
|
if _, found := t.managed[conn]; found {
|
||||||
delete(t.managed, conn)
|
delete(t.managed, conn)
|
||||||
} else {
|
} else {
|
||||||
logrus.Warnf("IdleTracker %p: StateClosed transition by un-managed connection", conn)
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"X-Reference-Id": fmt.Sprintf("%p", conn),
|
||||||
|
}).Warnf("IdleTracker: StateClosed transition by connection marked un-managed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
goRuntime "runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -17,11 +17,11 @@ import (
|
||||||
"github.com/containers/podman/v3/libpod/shutdown"
|
"github.com/containers/podman/v3/libpod/shutdown"
|
||||||
"github.com/containers/podman/v3/pkg/api/handlers"
|
"github.com/containers/podman/v3/pkg/api/handlers"
|
||||||
"github.com/containers/podman/v3/pkg/api/server/idle"
|
"github.com/containers/podman/v3/pkg/api/server/idle"
|
||||||
|
"github.com/containers/podman/v3/pkg/api/types"
|
||||||
"github.com/coreos/go-systemd/v22/activation"
|
"github.com/coreos/go-systemd/v22/activation"
|
||||||
"github.com/coreos/go-systemd/v22/daemon"
|
"github.com/coreos/go-systemd/v22/daemon"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,8 +44,10 @@ const (
|
||||||
UnlimitedServiceDuration = 0 * time.Second
|
UnlimitedServiceDuration = 0 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
// shutdownOnce ensures Shutdown() may safely be called from several go routines
|
// shutdownOnce ensures Shutdown() may safely be called from several go routines
|
||||||
var shutdownOnce sync.Once
|
shutdownOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
|
@ -66,15 +68,15 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
|
||||||
// If listener not provided try socket activation protocol
|
// If listener not provided try socket activation protocol
|
||||||
if listener == nil {
|
if listener == nil {
|
||||||
if _, found := os.LookupEnv("LISTEN_PID"); !found {
|
if _, found := os.LookupEnv("LISTEN_PID"); !found {
|
||||||
return nil, errors.Errorf("Cannot create API Server, no listener provided and socket activation protocol is not active.")
|
return nil, fmt.Errorf("no service listener provided and socket activation protocol is not active")
|
||||||
}
|
}
|
||||||
|
|
||||||
listeners, err := activation.Listeners()
|
listeners, err := activation.Listeners()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Cannot retrieve file descriptors from systemd")
|
return nil, fmt.Errorf("cannot retrieve file descriptors from systemd: %w", err)
|
||||||
}
|
}
|
||||||
if len(listeners) != 1 {
|
if len(listeners) != 1 {
|
||||||
return nil, errors.Errorf("Wrong number of file descriptors for socket activation protocol (%d != 1)", len(listeners))
|
return nil, fmt.Errorf("wrong number of file descriptors for socket activation protocol (%d != 1)", len(listeners))
|
||||||
}
|
}
|
||||||
listener = &listeners[0]
|
listener = &listeners[0]
|
||||||
}
|
}
|
||||||
|
@ -84,24 +86,35 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
|
||||||
logrus.Debugf("CORS Headers were set to %s", corsHeaders)
|
logrus.Debugf("CORS Headers were set to %s", corsHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Infof("API server listening on %q", (*listener).Addr())
|
logrus.Infof("API service listening on %q", (*listener).Addr())
|
||||||
router := mux.NewRouter().UseEncodedPath()
|
router := mux.NewRouter().UseEncodedPath()
|
||||||
idle := idle.NewTracker(duration)
|
tracker := idle.NewTracker(duration)
|
||||||
|
|
||||||
server := APIServer{
|
server := APIServer{
|
||||||
Server: http.Server{
|
Server: http.Server{
|
||||||
|
ConnContext: func(ctx context.Context, c net.Conn) context.Context {
|
||||||
|
return context.WithValue(ctx, types.ConnKey, c)
|
||||||
|
},
|
||||||
|
ConnState: tracker.ConnState,
|
||||||
|
ErrorLog: log.New(logrus.StandardLogger().Out, "", 0),
|
||||||
Handler: router,
|
Handler: router,
|
||||||
IdleTimeout: duration * 2,
|
IdleTimeout: duration * 2,
|
||||||
ConnState: idle.ConnState,
|
|
||||||
ErrorLog: log.New(logrus.StandardLogger().Out, "", 0),
|
|
||||||
},
|
},
|
||||||
Decoder: handlers.NewAPIDecoder(),
|
|
||||||
idleTracker: idle,
|
|
||||||
Listener: *listener,
|
|
||||||
Runtime: runtime,
|
|
||||||
CorsHeaders: corsHeaders,
|
CorsHeaders: corsHeaders,
|
||||||
|
Listener: *listener,
|
||||||
|
idleTracker: tracker,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server.BaseContext = func(l net.Listener) context.Context {
|
||||||
|
ctx := context.WithValue(context.Background(), types.DecoderKey, handlers.NewAPIDecoder())
|
||||||
|
ctx = context.WithValue(ctx, types.RuntimeKey, runtime)
|
||||||
|
ctx = context.WithValue(ctx, types.IdleTrackerKey, tracker)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture panics and print stack traces for diagnostics,
|
||||||
|
// additionally process X-Reference-Id Header to support event correlation
|
||||||
|
router.Use(panicHandler(), referenceIDHandler())
|
||||||
router.NotFoundHandler = http.HandlerFunc(
|
router.NotFoundHandler = http.HandlerFunc(
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
// We can track user errors...
|
// We can track user errors...
|
||||||
|
@ -149,6 +162,8 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
|
||||||
}
|
}
|
||||||
|
|
||||||
if logrus.IsLevelEnabled(logrus.TraceLevel) {
|
if logrus.IsLevelEnabled(logrus.TraceLevel) {
|
||||||
|
// If in trace mode log request and response bodies
|
||||||
|
router.Use(loggingHandler())
|
||||||
router.Walk(func(route *mux.Route, r *mux.Router, ancestors []*mux.Route) error { // nolint
|
router.Walk(func(route *mux.Route, r *mux.Router, ancestors []*mux.Route) error { // nolint
|
||||||
path, err := route.GetPathTemplate()
|
path, err := route.GetPathTemplate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -177,13 +192,13 @@ func setupSystemd() {
|
||||||
payload := fmt.Sprintf("MAINPID=%d\n", os.Getpid())
|
payload := fmt.Sprintf("MAINPID=%d\n", os.Getpid())
|
||||||
payload += daemon.SdNotifyReady
|
payload += daemon.SdNotifyReady
|
||||||
if sent, err := daemon.SdNotify(true, payload); err != nil {
|
if sent, err := daemon.SdNotify(true, payload); err != nil {
|
||||||
logrus.Errorf("Error notifying systemd of Conmon PID: %s", err.Error())
|
logrus.Error("API service error notifying systemd of Conmon PID: " + err.Error())
|
||||||
} else if !sent {
|
} else if !sent {
|
||||||
logrus.Warn("SDNotify not sent successfully")
|
logrus.Warn("API service unable to successfully send SDNotify")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Unsetenv("INVOCATION_ID"); err != nil {
|
if err := os.Unsetenv("INVOCATION_ID"); err != nil {
|
||||||
logrus.Errorf("Error unsetting INVOCATION_ID: %s", err.Error())
|
logrus.Error("API service failed unsetting INVOCATION_ID: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +220,7 @@ func (s *APIServer) Serve() error {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-s.idleTracker.Done()
|
<-s.idleTracker.Done()
|
||||||
logrus.Debugf("API Server idle for %s", s.idleTracker.Duration.Round(time.Second).String())
|
logrus.Debug("API service shutting down, idle for " + s.idleTracker.Duration.Round(time.Second).String())
|
||||||
_ = s.Shutdown()
|
_ = s.Shutdown()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -213,12 +228,12 @@ func (s *APIServer) Serve() error {
|
||||||
go func() {
|
go func() {
|
||||||
pprofMux := mux.NewRouter()
|
pprofMux := mux.NewRouter()
|
||||||
pprofMux.PathPrefix("/debug/pprof").Handler(http.DefaultServeMux)
|
pprofMux.PathPrefix("/debug/pprof").Handler(http.DefaultServeMux)
|
||||||
goRuntime.SetMutexProfileFraction(1)
|
runtime.SetMutexProfileFraction(1)
|
||||||
goRuntime.SetBlockProfileRate(1)
|
runtime.SetBlockProfileRate(1)
|
||||||
s.pprof = &http.Server{Addr: "localhost:8888", Handler: pprofMux}
|
s.pprof = &http.Server{Addr: "localhost:8888", Handler: pprofMux}
|
||||||
err := s.pprof.ListenAndServe()
|
err := s.pprof.ListenAndServe()
|
||||||
if err != nil && err != http.ErrServerClosed {
|
if err != nil && err != http.ErrServerClosed {
|
||||||
logrus.Warn("Profiler Service failed: " + err.Error())
|
logrus.Warn("API profiler service failed: " + err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -230,7 +245,7 @@ func (s *APIServer) Serve() error {
|
||||||
go func() {
|
go func() {
|
||||||
err := s.Server.Serve(s.Listener)
|
err := s.Server.Serve(s.Listener)
|
||||||
if err != nil && err != http.ErrServerClosed {
|
if err != nil && err != http.ErrServerClosed {
|
||||||
errChan <- errors.Wrap(err, "failed to start API server")
|
errChan <- fmt.Errorf("failed to start API service: %w", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errChan <- nil
|
errChan <- nil
|
||||||
|
@ -242,14 +257,14 @@ func (s *APIServer) Serve() error {
|
||||||
// Shutdown is a clean shutdown waiting on existing clients
|
// Shutdown is a clean shutdown waiting on existing clients
|
||||||
func (s *APIServer) Shutdown() error {
|
func (s *APIServer) Shutdown() error {
|
||||||
if s.idleTracker.Duration == UnlimitedServiceDuration {
|
if s.idleTracker.Duration == UnlimitedServiceDuration {
|
||||||
logrus.Debug("APIServer.Shutdown ignored as Duration is UnlimitedService")
|
logrus.Debug("API service shutdown ignored as Duration is UnlimitedService")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdownOnce.Do(func() {
|
shutdownOnce.Do(func() {
|
||||||
if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
||||||
_, file, line, _ := goRuntime.Caller(1)
|
_, file, line, _ := runtime.Caller(1)
|
||||||
logrus.Debugf("APIServer.Shutdown by %s:%d, %d/%d connection(s)",
|
logrus.Debugf("API service shutdown by %s:%d, %d/%d connection(s)",
|
||||||
file, line, s.idleTracker.ActiveConnections(), s.idleTracker.TotalConnections())
|
file, line, s.idleTracker.ActiveConnections(), s.idleTracker.TotalConnections())
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -257,8 +272,7 @@ func (s *APIServer) Shutdown() error {
|
||||||
go func() {
|
go func() {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if err := s.pprof.Shutdown(ctx); err != nil {
|
if err := s.pprof.Shutdown(ctx); err != nil {
|
||||||
logrus.Warn(
|
logrus.Warn("Failed to cleanly shutdown API pprof service: " + err.Error())
|
||||||
errors.Wrapf(err, "failed to cleanly shutdown pprof Server"))
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
@ -272,8 +286,7 @@ func (s *APIServer) Shutdown() error {
|
||||||
|
|
||||||
err := s.Server.Shutdown(ctx)
|
err := s.Server.Shutdown(ctx)
|
||||||
if err != nil && err != context.Canceled && err != http.ErrServerClosed {
|
if err != nil && err != context.Canceled && err != http.ErrServerClosed {
|
||||||
logrus.Error(
|
logrus.Error("Failed to cleanly shutdown API service: " + err.Error())
|
||||||
errors.Wrapf(err, "failed to cleanly shutdown APIServer"))
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultAPIVersion is the version of the API the server defaults to.
|
// DefaultAPIVersion is the version of the compatible API the server defaults to
|
||||||
DefaultAPIVersion = "1.40" // See https://docs.docker.com/engine/api/v1.40/
|
DefaultAPIVersion = "1.40" // See https://docs.docker.com/engine/api/v1.40/
|
||||||
|
|
||||||
// DefaultAPIVersion is the minimal required version of the API.
|
// MinimalAPIVersion is the minimal required version of the compatible API
|
||||||
MinimalAPIVersion = "1.24"
|
MinimalAPIVersion = "1.24"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type APIContextKey int
|
||||||
|
|
||||||
|
const (
|
||||||
|
DecoderKey APIContextKey = iota
|
||||||
|
RuntimeKey
|
||||||
|
IdleTrackerKey
|
||||||
|
ConnKey
|
||||||
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import json
|
import json
|
||||||
import unittest
|
import unittest
|
||||||
|
import uuid
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from .fixtures import APITestCase
|
from .fixtures import APITestCase
|
||||||
|
@ -92,6 +93,18 @@ class SystemTestCase(APITestCase):
|
||||||
r = requests.get(self.uri("/system/df"))
|
r = requests.get(self.uri("/system/df"))
|
||||||
self.assertEqual(r.status_code, 200, r.text)
|
self.assertEqual(r.status_code, 200, r.text)
|
||||||
|
|
||||||
|
def test_reference_id(self):
|
||||||
|
rid = str(uuid.uuid4())
|
||||||
|
r = requests.get(self.uri("/info"), headers={"X-Reference-Id": rid})
|
||||||
|
self.assertEqual(r.status_code, 200, r.text)
|
||||||
|
|
||||||
|
self.assertIn("X-Reference-Id", r.headers)
|
||||||
|
self.assertEqual(r.headers["X-Reference-Id"], rid)
|
||||||
|
|
||||||
|
r = requests.get(self.uri("/info"))
|
||||||
|
self.assertIn("X-Reference-Id", r.headers)
|
||||||
|
self.assertNotEqual(r.headers["X-Reference-Id"], rid)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.1
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- tip
|
|
@ -0,0 +1,22 @@
|
||||||
|
Copyright (c) 2013 The Gorilla Handlers Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,52 @@
|
||||||
|
gorilla/handlers
|
||||||
|
================
|
||||||
|
[](https://godoc.org/github.com/gorilla/handlers) [](https://travis-ci.org/gorilla/handlers)
|
||||||
|
|
||||||
|
Package handlers is a collection of handlers (aka "HTTP middleware") for use
|
||||||
|
with Go's `net/http` package (or any framework supporting `http.Handler`), including:
|
||||||
|
|
||||||
|
* `LoggingHandler` for logging HTTP requests in the Apache [Common Log
|
||||||
|
Format](http://httpd.apache.org/docs/2.2/logs.html#common).
|
||||||
|
* `CombinedLoggingHandler` for logging HTTP requests in the Apache [Combined Log
|
||||||
|
Format](http://httpd.apache.org/docs/2.2/logs.html#combined) commonly used by
|
||||||
|
both Apache and nginx.
|
||||||
|
* `CompressHandler` for gzipping responses.
|
||||||
|
* `ContentTypeHandler` for validating requests against a list of accepted
|
||||||
|
content types.
|
||||||
|
* `MethodHandler` for matching HTTP methods against handlers in a
|
||||||
|
`map[string]http.Handler`
|
||||||
|
* `ProxyHeaders` for populating `r.RemoteAddr` and `r.URL.Scheme` based on the
|
||||||
|
`X-Forwarded-For`, `X-Real-IP`, `X-Forwarded-Proto` and RFC7239 `Forwarded`
|
||||||
|
headers when running a Go server behind a HTTP reverse proxy.
|
||||||
|
* `CanonicalHost` for re-directing to the preferred host when handling multiple
|
||||||
|
domains (i.e. multiple CNAME aliases).
|
||||||
|
|
||||||
|
Other handlers are documented [on the Gorilla
|
||||||
|
website](http://www.gorillatoolkit.org/pkg/handlers).
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
A simple example using `handlers.LoggingHandler` and `handlers.CompressHandler`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"github.com/gorilla/handlers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r := http.NewServeMux()
|
||||||
|
|
||||||
|
// Only log requests to our admin dashboard to stdout
|
||||||
|
r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard)))
|
||||||
|
r.HandleFunc("/", ShowIndex)
|
||||||
|
|
||||||
|
// Wrap our server with our gzip handler to gzip compress all responses.
|
||||||
|
http.ListenAndServe(":8000", handlers.CompressHandler(r))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
BSD licensed. See the included LICENSE file for details.
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type canonical struct {
|
||||||
|
h http.Handler
|
||||||
|
domain string
|
||||||
|
code int
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanonicalHost is HTTP middleware that re-directs requests to the canonical
|
||||||
|
// domain. It accepts a domain and a status code (e.g. 301 or 302) and
|
||||||
|
// re-directs clients to this domain. The existing request path is maintained.
|
||||||
|
//
|
||||||
|
// Note: If the provided domain is considered invalid by url.Parse or otherwise
|
||||||
|
// returns an empty scheme or host, clients are not re-directed.
|
||||||
|
// not re-directed.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// r := mux.NewRouter()
|
||||||
|
// canonical := handlers.CanonicalHost("http://www.gorillatoolkit.org", 302)
|
||||||
|
// r.HandleFunc("/route", YourHandler)
|
||||||
|
//
|
||||||
|
// log.Fatal(http.ListenAndServe(":7000", canonical(r)))
|
||||||
|
//
|
||||||
|
func CanonicalHost(domain string, code int) func(h http.Handler) http.Handler {
|
||||||
|
fn := func(h http.Handler) http.Handler {
|
||||||
|
return canonical{h, domain, code}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c canonical) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dest, err := url.Parse(c.domain)
|
||||||
|
if err != nil {
|
||||||
|
// Call the next handler if the provided domain fails to parse.
|
||||||
|
c.h.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if dest.Scheme == "" || dest.Host == "" {
|
||||||
|
// Call the next handler if the scheme or host are empty.
|
||||||
|
// Note that url.Parse won't fail on in this case.
|
||||||
|
c.h.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.EqualFold(cleanHost(r.Host), dest.Host) {
|
||||||
|
// Re-build the destination URL
|
||||||
|
dest := dest.Scheme + "://" + dest.Host + r.URL.Path
|
||||||
|
http.Redirect(w, r, dest, c.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.h.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanHost cleans invalid Host headers by stripping anything after '/' or ' '.
|
||||||
|
// This is backported from Go 1.5 (in response to issue #11206) and attempts to
|
||||||
|
// mitigate malformed Host headers that do not match the format in RFC7230.
|
||||||
|
func cleanHost(in string) string {
|
||||||
|
if i := strings.IndexAny(in, " /"); i != -1 {
|
||||||
|
return in[:i]
|
||||||
|
}
|
||||||
|
return in
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright 2013 The Gorilla Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/flate"
|
||||||
|
"compress/gzip"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type compressResponseWriter struct {
|
||||||
|
io.Writer
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *compressResponseWriter) Header() http.Header {
|
||||||
|
return w.ResponseWriter.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *compressResponseWriter) Write(b []byte) (int, error) {
|
||||||
|
h := w.ResponseWriter.Header()
|
||||||
|
if h.Get("Content-Type") == "" {
|
||||||
|
h.Set("Content-Type", http.DetectContentType(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.Writer.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompressHandler gzip compresses HTTP responses for clients that support it
|
||||||
|
// via the 'Accept-Encoding' header.
|
||||||
|
func CompressHandler(h http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
L:
|
||||||
|
for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") {
|
||||||
|
switch strings.TrimSpace(enc) {
|
||||||
|
case "gzip":
|
||||||
|
w.Header().Set("Content-Encoding", "gzip")
|
||||||
|
w.Header().Add("Vary", "Accept-Encoding")
|
||||||
|
|
||||||
|
gw := gzip.NewWriter(w)
|
||||||
|
defer gw.Close()
|
||||||
|
|
||||||
|
h, hok := w.(http.Hijacker)
|
||||||
|
if !hok { /* w is not Hijacker... oh well... */
|
||||||
|
h = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
w = &compressResponseWriter{
|
||||||
|
Writer: gw,
|
||||||
|
ResponseWriter: w,
|
||||||
|
Hijacker: h,
|
||||||
|
}
|
||||||
|
|
||||||
|
break L
|
||||||
|
case "deflate":
|
||||||
|
w.Header().Set("Content-Encoding", "deflate")
|
||||||
|
w.Header().Add("Vary", "Accept-Encoding")
|
||||||
|
|
||||||
|
fw, _ := flate.NewWriter(w, flate.DefaultCompression)
|
||||||
|
defer fw.Close()
|
||||||
|
|
||||||
|
h, hok := w.(http.Hijacker)
|
||||||
|
if !hok { /* w is not Hijacker... oh well... */
|
||||||
|
h = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
w = &compressResponseWriter{
|
||||||
|
Writer: fw,
|
||||||
|
ResponseWriter: w,
|
||||||
|
Hijacker: h,
|
||||||
|
}
|
||||||
|
|
||||||
|
break L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
Package handlers is a collection of handlers (aka "HTTP middleware") for use
|
||||||
|
with Go's net/http package (or any framework supporting http.Handler).
|
||||||
|
|
||||||
|
The package includes handlers for logging in standardised formats, compressing
|
||||||
|
HTTP responses, validating content types and other useful tools for manipulating
|
||||||
|
requests and responses.
|
||||||
|
*/
|
||||||
|
package handlers
|
|
@ -0,0 +1,378 @@
|
||||||
|
// Copyright 2013 The Gorilla Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MethodHandler is an http.Handler that dispatches to a handler whose key in the MethodHandler's
|
||||||
|
// map matches the name of the HTTP request's method, eg: GET
|
||||||
|
//
|
||||||
|
// If the request's method is OPTIONS and OPTIONS is not a key in the map then the handler
|
||||||
|
// responds with a status of 200 and sets the Allow header to a comma-separated list of
|
||||||
|
// available methods.
|
||||||
|
//
|
||||||
|
// If the request's method doesn't match any of its keys the handler responds with
|
||||||
|
// a status of 405, Method not allowed and sets the Allow header to a comma-separated list
|
||||||
|
// of available methods.
|
||||||
|
type MethodHandler map[string]http.Handler
|
||||||
|
|
||||||
|
func (h MethodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
if handler, ok := h[req.Method]; ok {
|
||||||
|
handler.ServeHTTP(w, req)
|
||||||
|
} else {
|
||||||
|
allow := []string{}
|
||||||
|
for k := range h {
|
||||||
|
allow = append(allow, k)
|
||||||
|
}
|
||||||
|
sort.Strings(allow)
|
||||||
|
w.Header().Set("Allow", strings.Join(allow, ", "))
|
||||||
|
if req.Method == "OPTIONS" {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
} else {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its friends
|
||||||
|
type loggingHandler struct {
|
||||||
|
writer io.Writer
|
||||||
|
handler http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// combinedLoggingHandler is the http.Handler implementation for LoggingHandlerTo and its friends
|
||||||
|
type combinedLoggingHandler struct {
|
||||||
|
writer io.Writer
|
||||||
|
handler http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
t := time.Now()
|
||||||
|
logger := makeLogger(w)
|
||||||
|
url := *req.URL
|
||||||
|
h.handler.ServeHTTP(logger, req)
|
||||||
|
writeLog(h.writer, req, url, t, logger.Status(), logger.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h combinedLoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
t := time.Now()
|
||||||
|
logger := makeLogger(w)
|
||||||
|
url := *req.URL
|
||||||
|
h.handler.ServeHTTP(logger, req)
|
||||||
|
writeCombinedLog(h.writer, req, url, t, logger.Status(), logger.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeLogger(w http.ResponseWriter) loggingResponseWriter {
|
||||||
|
var logger loggingResponseWriter = &responseLogger{w: w}
|
||||||
|
if _, ok := w.(http.Hijacker); ok {
|
||||||
|
logger = &hijackLogger{responseLogger{w: w}}
|
||||||
|
}
|
||||||
|
h, ok1 := logger.(http.Hijacker)
|
||||||
|
c, ok2 := w.(http.CloseNotifier)
|
||||||
|
if ok1 && ok2 {
|
||||||
|
return hijackCloseNotifier{logger, h, c}
|
||||||
|
}
|
||||||
|
if ok2 {
|
||||||
|
return &closeNotifyWriter{logger, c}
|
||||||
|
}
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type loggingResponseWriter interface {
|
||||||
|
http.ResponseWriter
|
||||||
|
http.Flusher
|
||||||
|
Status() int
|
||||||
|
Size() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP status
|
||||||
|
// code and body size
|
||||||
|
type responseLogger struct {
|
||||||
|
w http.ResponseWriter
|
||||||
|
status int
|
||||||
|
size int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *responseLogger) Header() http.Header {
|
||||||
|
return l.w.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *responseLogger) Write(b []byte) (int, error) {
|
||||||
|
if l.status == 0 {
|
||||||
|
// The status will be StatusOK if WriteHeader has not been called yet
|
||||||
|
l.status = http.StatusOK
|
||||||
|
}
|
||||||
|
size, err := l.w.Write(b)
|
||||||
|
l.size += size
|
||||||
|
return size, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *responseLogger) WriteHeader(s int) {
|
||||||
|
l.w.WriteHeader(s)
|
||||||
|
l.status = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *responseLogger) Status() int {
|
||||||
|
return l.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *responseLogger) Size() int {
|
||||||
|
return l.size
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *responseLogger) Flush() {
|
||||||
|
f, ok := l.w.(http.Flusher)
|
||||||
|
if ok {
|
||||||
|
f.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type hijackLogger struct {
|
||||||
|
responseLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *hijackLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
h := l.responseLogger.w.(http.Hijacker)
|
||||||
|
conn, rw, err := h.Hijack()
|
||||||
|
if err == nil && l.responseLogger.status == 0 {
|
||||||
|
// The status will be StatusSwitchingProtocols if there was no error and WriteHeader has not been called yet
|
||||||
|
l.responseLogger.status = http.StatusSwitchingProtocols
|
||||||
|
}
|
||||||
|
return conn, rw, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type closeNotifyWriter struct {
|
||||||
|
loggingResponseWriter
|
||||||
|
http.CloseNotifier
|
||||||
|
}
|
||||||
|
|
||||||
|
type hijackCloseNotifier struct {
|
||||||
|
loggingResponseWriter
|
||||||
|
http.Hijacker
|
||||||
|
http.CloseNotifier
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerhex = "0123456789abcdef"
|
||||||
|
|
||||||
|
func appendQuoted(buf []byte, s string) []byte {
|
||||||
|
var runeTmp [utf8.UTFMax]byte
|
||||||
|
for width := 0; len(s) > 0; s = s[width:] {
|
||||||
|
r := rune(s[0])
|
||||||
|
width = 1
|
||||||
|
if r >= utf8.RuneSelf {
|
||||||
|
r, width = utf8.DecodeRuneInString(s)
|
||||||
|
}
|
||||||
|
if width == 1 && r == utf8.RuneError {
|
||||||
|
buf = append(buf, `\x`...)
|
||||||
|
buf = append(buf, lowerhex[s[0]>>4])
|
||||||
|
buf = append(buf, lowerhex[s[0]&0xF])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r == rune('"') || r == '\\' { // always backslashed
|
||||||
|
buf = append(buf, '\\')
|
||||||
|
buf = append(buf, byte(r))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strconv.IsPrint(r) {
|
||||||
|
n := utf8.EncodeRune(runeTmp[:], r)
|
||||||
|
buf = append(buf, runeTmp[:n]...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case '\a':
|
||||||
|
buf = append(buf, `\a`...)
|
||||||
|
case '\b':
|
||||||
|
buf = append(buf, `\b`...)
|
||||||
|
case '\f':
|
||||||
|
buf = append(buf, `\f`...)
|
||||||
|
case '\n':
|
||||||
|
buf = append(buf, `\n`...)
|
||||||
|
case '\r':
|
||||||
|
buf = append(buf, `\r`...)
|
||||||
|
case '\t':
|
||||||
|
buf = append(buf, `\t`...)
|
||||||
|
case '\v':
|
||||||
|
buf = append(buf, `\v`...)
|
||||||
|
default:
|
||||||
|
switch {
|
||||||
|
case r < ' ':
|
||||||
|
buf = append(buf, `\x`...)
|
||||||
|
buf = append(buf, lowerhex[s[0]>>4])
|
||||||
|
buf = append(buf, lowerhex[s[0]&0xF])
|
||||||
|
case r > utf8.MaxRune:
|
||||||
|
r = 0xFFFD
|
||||||
|
fallthrough
|
||||||
|
case r < 0x10000:
|
||||||
|
buf = append(buf, `\u`...)
|
||||||
|
for s := 12; s >= 0; s -= 4 {
|
||||||
|
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
buf = append(buf, `\U`...)
|
||||||
|
for s := 28; s >= 0; s -= 4 {
|
||||||
|
buf = append(buf, lowerhex[r>>uint(s)&0xF])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildCommonLogLine builds a log entry for req in Apache Common Log Format.
|
||||||
|
// ts is the timestamp with which the entry should be logged.
|
||||||
|
// status and size are used to provide the response HTTP status and size.
|
||||||
|
func buildCommonLogLine(req *http.Request, url url.URL, ts time.Time, status int, size int) []byte {
|
||||||
|
username := "-"
|
||||||
|
if url.User != nil {
|
||||||
|
if name := url.User.Username(); name != "" {
|
||||||
|
username = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
host = req.RemoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := url.RequestURI()
|
||||||
|
|
||||||
|
buf := make([]byte, 0, 3*(len(host)+len(username)+len(req.Method)+len(uri)+len(req.Proto)+50)/2)
|
||||||
|
buf = append(buf, host...)
|
||||||
|
buf = append(buf, " - "...)
|
||||||
|
buf = append(buf, username...)
|
||||||
|
buf = append(buf, " ["...)
|
||||||
|
buf = append(buf, ts.Format("02/Jan/2006:15:04:05 -0700")...)
|
||||||
|
buf = append(buf, `] "`...)
|
||||||
|
buf = append(buf, req.Method...)
|
||||||
|
buf = append(buf, " "...)
|
||||||
|
buf = appendQuoted(buf, uri)
|
||||||
|
buf = append(buf, " "...)
|
||||||
|
buf = append(buf, req.Proto...)
|
||||||
|
buf = append(buf, `" `...)
|
||||||
|
buf = append(buf, strconv.Itoa(status)...)
|
||||||
|
buf = append(buf, " "...)
|
||||||
|
buf = append(buf, strconv.Itoa(size)...)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeLog writes a log entry for req to w in Apache Common Log Format.
|
||||||
|
// ts is the timestamp with which the entry should be logged.
|
||||||
|
// status and size are used to provide the response HTTP status and size.
|
||||||
|
func writeLog(w io.Writer, req *http.Request, url url.URL, ts time.Time, status, size int) {
|
||||||
|
buf := buildCommonLogLine(req, url, ts, status, size)
|
||||||
|
buf = append(buf, '\n')
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeCombinedLog writes a log entry for req to w in Apache Combined Log Format.
|
||||||
|
// ts is the timestamp with which the entry should be logged.
|
||||||
|
// status and size are used to provide the response HTTP status and size.
|
||||||
|
func writeCombinedLog(w io.Writer, req *http.Request, url url.URL, ts time.Time, status, size int) {
|
||||||
|
buf := buildCommonLogLine(req, url, ts, status, size)
|
||||||
|
buf = append(buf, ` "`...)
|
||||||
|
buf = appendQuoted(buf, req.Referer())
|
||||||
|
buf = append(buf, `" "`...)
|
||||||
|
buf = appendQuoted(buf, req.UserAgent())
|
||||||
|
buf = append(buf, '"', '\n')
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CombinedLoggingHandler return a http.Handler that wraps h and logs requests to out in
|
||||||
|
// Apache Combined Log Format.
|
||||||
|
//
|
||||||
|
// See http://httpd.apache.org/docs/2.2/logs.html#combined for a description of this format.
|
||||||
|
//
|
||||||
|
// LoggingHandler always sets the ident field of the log to -
|
||||||
|
func CombinedLoggingHandler(out io.Writer, h http.Handler) http.Handler {
|
||||||
|
return combinedLoggingHandler{out, h}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoggingHandler return a http.Handler that wraps h and logs requests to out in
|
||||||
|
// Apache Common Log Format (CLF).
|
||||||
|
//
|
||||||
|
// See http://httpd.apache.org/docs/2.2/logs.html#common for a description of this format.
|
||||||
|
//
|
||||||
|
// LoggingHandler always sets the ident field of the log to -
|
||||||
|
func LoggingHandler(out io.Writer, h http.Handler) http.Handler {
|
||||||
|
return loggingHandler{out, h}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isContentType validates the Content-Type header
|
||||||
|
// is contentType. That is, its type and subtype match.
|
||||||
|
func isContentType(h http.Header, contentType string) bool {
|
||||||
|
ct := h.Get("Content-Type")
|
||||||
|
if i := strings.IndexRune(ct, ';'); i != -1 {
|
||||||
|
ct = ct[0:i]
|
||||||
|
}
|
||||||
|
return ct == contentType
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContentTypeHandler wraps and returns a http.Handler, validating the request content type
|
||||||
|
// is acompatible with the contentTypes list.
|
||||||
|
// It writes a HTTP 415 error if that fails.
|
||||||
|
//
|
||||||
|
// Only PUT, POST, and PATCH requests are considered.
|
||||||
|
func ContentTypeHandler(h http.Handler, contentTypes ...string) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !(r.Method == "PUT" || r.Method == "POST" || r.Method == "PATCH") {
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ct := range contentTypes {
|
||||||
|
if isContentType(r.Header, ct) {
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
http.Error(w, fmt.Sprintf("Unsupported content type %q; expected one of %q", r.Header.Get("Content-Type"), contentTypes), http.StatusUnsupportedMediaType)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// HTTPMethodOverrideHeader is a commonly used
|
||||||
|
// http header to override a request method.
|
||||||
|
HTTPMethodOverrideHeader = "X-HTTP-Method-Override"
|
||||||
|
// HTTPMethodOverrideFormKey is a commonly used
|
||||||
|
// HTML form key to override a request method.
|
||||||
|
HTTPMethodOverrideFormKey = "_method"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HTTPMethodOverrideHandler wraps and returns a http.Handler which checks for the X-HTTP-Method-Override header
|
||||||
|
// or the _method form key, and overrides (if valid) request.Method with its value.
|
||||||
|
//
|
||||||
|
// This is especially useful for http clients that don't support many http verbs.
|
||||||
|
// It isn't secure to override e.g a GET to a POST, so only POST requests are considered.
|
||||||
|
// Likewise, the override method can only be a "write" method: PUT, PATCH or DELETE.
|
||||||
|
//
|
||||||
|
// Form method takes precedence over header method.
|
||||||
|
func HTTPMethodOverrideHandler(h http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method == "POST" {
|
||||||
|
om := r.FormValue(HTTPMethodOverrideFormKey)
|
||||||
|
if om == "" {
|
||||||
|
om = r.Header.Get(HTTPMethodOverrideHeader)
|
||||||
|
}
|
||||||
|
if om == "PUT" || om == "PATCH" || om == "DELETE" {
|
||||||
|
r.Method = om
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// De-facto standard header keys.
|
||||||
|
xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
|
||||||
|
xRealIP = http.CanonicalHeaderKey("X-Real-IP")
|
||||||
|
xForwardedProto = http.CanonicalHeaderKey("X-Forwarded-Scheme")
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// RFC7239 defines a new "Forwarded: " header designed to replace the
|
||||||
|
// existing use of X-Forwarded-* headers.
|
||||||
|
// e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43
|
||||||
|
forwarded = http.CanonicalHeaderKey("Forwarded")
|
||||||
|
// Allows for a sub-match of the first value after 'for=' to the next
|
||||||
|
// comma, semi-colon or space. The match is case-insensitive.
|
||||||
|
forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)`)
|
||||||
|
// Allows for a sub-match for the first instance of scheme (http|https)
|
||||||
|
// prefixed by 'proto='. The match is case-insensitive.
|
||||||
|
protoRegex = regexp.MustCompile(`(?i)(?:proto=)(https|http)`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProxyHeaders inspects common reverse proxy headers and sets the corresponding
|
||||||
|
// fields in the HTTP request struct. These are X-Forwarded-For and X-Real-IP
|
||||||
|
// for the remote (client) IP address, X-Forwarded-Proto for the scheme
|
||||||
|
// (http|https) and the RFC7239 Forwarded header, which may include both client
|
||||||
|
// IPs and schemes.
|
||||||
|
//
|
||||||
|
// NOTE: This middleware should only be used when behind a reverse
|
||||||
|
// proxy like nginx, HAProxy or Apache. Reverse proxies that don't (or are
|
||||||
|
// configured not to) strip these headers from client requests, or where these
|
||||||
|
// headers are accepted "as is" from a remote client (e.g. when Go is not behind
|
||||||
|
// a proxy), can manifest as a vulnerability if your application uses these
|
||||||
|
// headers for validating the 'trustworthiness' of a request.
|
||||||
|
func ProxyHeaders(h http.Handler) http.Handler {
|
||||||
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Set the remote IP with the value passed from the proxy.
|
||||||
|
if fwd := getIP(r); fwd != "" {
|
||||||
|
r.RemoteAddr = fwd
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the scheme (proto) with the value passed from the proxy.
|
||||||
|
if scheme := getScheme(r); scheme != "" {
|
||||||
|
r.URL.Scheme = scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the next handler in the chain.
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandlerFunc(fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getIP retrieves the IP from the X-Forwarded-For, X-Real-IP and RFC7239
|
||||||
|
// Forwarded headers (in that order).
|
||||||
|
func getIP(r *http.Request) string {
|
||||||
|
var addr string
|
||||||
|
|
||||||
|
if fwd := r.Header.Get(xForwardedFor); fwd != "" {
|
||||||
|
// Only grab the first (client) address. Note that '192.168.0.1,
|
||||||
|
// 10.1.1.1' is a valid key for X-Forwarded-For where addresses after
|
||||||
|
// the first may represent forwarding proxies earlier in the chain.
|
||||||
|
s := strings.Index(fwd, ", ")
|
||||||
|
if s == -1 {
|
||||||
|
s = len(fwd)
|
||||||
|
}
|
||||||
|
addr = fwd[:s]
|
||||||
|
} else if fwd := r.Header.Get(xRealIP); fwd != "" {
|
||||||
|
// X-Real-IP should only contain one IP address (the client making the
|
||||||
|
// request).
|
||||||
|
addr = fwd
|
||||||
|
} else if fwd := r.Header.Get(forwarded); fwd != "" {
|
||||||
|
// match should contain at least two elements if the protocol was
|
||||||
|
// specified in the Forwarded header. The first element will always be
|
||||||
|
// the 'for=' capture, which we ignore. In the case of multiple IP
|
||||||
|
// addresses (for=8.8.8.8, 8.8.4.4,172.16.1.20 is valid) we only
|
||||||
|
// extract the first, which should be the client IP.
|
||||||
|
if match := forRegex.FindStringSubmatch(fwd); len(match) > 1 {
|
||||||
|
// IPv6 addresses in Forwarded headers are quoted-strings. We strip
|
||||||
|
// these quotes.
|
||||||
|
addr = strings.Trim(match[1], `"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// getScheme retrieves the scheme from the X-Forwarded-Proto and RFC7239
|
||||||
|
// Forwarded headers (in that order).
|
||||||
|
func getScheme(r *http.Request) string {
|
||||||
|
var scheme string
|
||||||
|
|
||||||
|
// Retrieve the scheme from X-Forwarded-Proto.
|
||||||
|
if proto := r.Header.Get(xForwardedProto); proto != "" {
|
||||||
|
scheme = strings.ToLower(proto)
|
||||||
|
} else if proto := r.Header.Get(forwarded); proto != "" {
|
||||||
|
// match should contain at least two elements if the protocol was
|
||||||
|
// specified in the Forwarded header. The first element will always be
|
||||||
|
// the 'proto=' capture, which we ignore. In the case of multiple proto
|
||||||
|
// parameters (invalid) we only extract the first.
|
||||||
|
if match := protoRegex.FindStringSubmatch(proto); len(match) > 1 {
|
||||||
|
scheme = strings.ToLower(match[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scheme
|
||||||
|
}
|
|
@ -379,6 +379,8 @@ github.com/google/gofuzz
|
||||||
github.com/google/shlex
|
github.com/google/shlex
|
||||||
# github.com/google/uuid v1.3.0
|
# github.com/google/uuid v1.3.0
|
||||||
github.com/google/uuid
|
github.com/google/uuid
|
||||||
|
# github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33
|
||||||
|
github.com/gorilla/handlers
|
||||||
# github.com/gorilla/mux v1.8.0
|
# github.com/gorilla/mux v1.8.0
|
||||||
github.com/gorilla/mux
|
github.com/gorilla/mux
|
||||||
# github.com/gorilla/schema v1.2.0
|
# github.com/gorilla/schema v1.2.0
|
||||||
|
|
Loading…
Reference in New Issue