summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorChristian Stewart <christian@paral.in>2022-03-23 00:21:48 -0700
committerChristian Stewart <christian@paral.in>2022-03-24 00:57:01 -0700
commit752680366c5896da6587d892ba719eb35dd1a859 (patch)
tree2fd3db0fa8fe1179b7f4dd77e3664e83fa811319 /pkg
parent80123ca505081fca513fc0865cf6e2daf43ff854 (diff)
downloadpodman-752680366c5896da6587d892ba719eb35dd1a859.tar.gz
podman-752680366c5896da6587d892ba719eb35dd1a859.tar.bz2
podman-752680366c5896da6587d892ba719eb35dd1a859.zip
play: kube: use in-memory kubefile and remove tempfile
The PlayKube and PlayKubeDown commands accepted a "path" argument to a YAML file to play. This requires the caller to write the YAML to a file path. The downside of this is apparent in the HTTP handlers which have to use a temporary file on disk to store the YAML file. The file is opened & used as the body of the HTTP request. It's possible to instead pass a io.Reader and use a fully in-memory request body. Add backwards-compatible changes to bindings to allow passing either a filepath or a io.Reader body. Refactor the podman bindings to use a io.Reader instead of a filepath. Simplify the HTTP handlers for PlayKube by removing the now unneeded tempfile. [NO NEW TESTS NEEDED] Signed-off-by: Christian Stewart <christian@paral.in>
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/libpod/play.go53
-rw-r--r--pkg/bindings/play/play.go39
-rw-r--r--pkg/domain/entities/engine_container.go4
-rw-r--r--pkg/domain/infra/abi/play.go28
-rw-r--r--pkg/domain/infra/tunnel/play.go9
5 files changed, 50 insertions, 83 deletions
diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go
index aed889298..ca9ada761 100644
--- a/pkg/api/handlers/libpod/play.go
+++ b/pkg/api/handlers/libpod/play.go
@@ -1,11 +1,8 @@
package libpod
import (
- "io"
- "io/ioutil"
"net"
"net/http"
- "os"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/libpod"
@@ -16,7 +13,6 @@ import (
"github.com/containers/podman/v4/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
func PlayKube(w http.ResponseWriter, r *http.Request) {
@@ -62,28 +58,6 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
staticMACs = append(staticMACs, mac)
}
- // Fetch the K8s YAML file from the body, and copy it to a temp file.
- tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
- if err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
- return
- }
- defer func() {
- if err := os.Remove(tmpfile.Name()); err != nil {
- logrus.Warn(err)
- }
- }()
- if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF {
- if err := tmpfile.Close(); err != nil {
- logrus.Warn(err)
- }
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
- return
- }
- if err := tmpfile.Close(); err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error closing temporary file"))
- return
- }
authConf, authfile, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, http.StatusBadRequest, err)
@@ -116,7 +90,8 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
if _, found := r.URL.Query()["start"]; found {
options.Start = types.NewOptionalBool(query.Start)
}
- report, err := containerEngine.PlayKube(r.Context(), tmpfile.Name(), options)
+ report, err := containerEngine.PlayKube(r.Context(), r.Body, options)
+ _ = r.Body.Close()
if err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error playing YAML file"))
return
@@ -126,30 +101,10 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
func PlayKubeDown(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
- tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
- if err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
- return
- }
- defer func() {
- if err := os.Remove(tmpfile.Name()); err != nil {
- logrus.Warn(err)
- }
- }()
- if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF {
- if err := tmpfile.Close(); err != nil {
- logrus.Warn(err)
- }
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
- return
- }
- if err := tmpfile.Close(); err != nil {
- utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error closing temporary file"))
- return
- }
containerEngine := abi.ContainerEngine{Libpod: runtime}
options := new(entities.PlayKubeDownOptions)
- report, err := containerEngine.PlayKubeDown(r.Context(), tmpfile.Name(), *options)
+ report, err := containerEngine.PlayKubeDown(r.Context(), r.Body, *options)
+ _ = r.Body.Close()
if err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error tearing down YAML file"))
return
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index d4018b6b3..8058a8514 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -2,6 +2,7 @@ package play
import (
"context"
+ "io"
"net/http"
"os"
"strconv"
@@ -14,20 +15,25 @@ import (
)
func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.PlayKubeReport, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return KubeWithBody(ctx, f, options)
+}
+
+func KubeWithBody(ctx context.Context, body io.Reader, options *KubeOptions) (*entities.PlayKubeReport, error) {
var report entities.PlayKubeReport
if options == nil {
options = new(KubeOptions)
}
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
- f, err := os.Open(path)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
- defer f.Close()
params, err := options.ToParams()
if err != nil {
@@ -46,7 +52,7 @@ func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.Pla
return nil, err
}
- response, err := conn.DoRequest(ctx, f, http.MethodPost, "/play/kube", params, header)
+ response, err := conn.DoRequest(ctx, body, http.MethodPost, "/play/kube", params, header)
if err != nil {
return nil, err
}
@@ -60,12 +66,6 @@ func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.Pla
}
func KubeDown(ctx context.Context, path string) (*entities.PlayKubeReport, error) {
- var report entities.PlayKubeReport
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
-
f, err := os.Open(path)
if err != nil {
return nil, err
@@ -75,7 +75,18 @@ func KubeDown(ctx context.Context, path string) (*entities.PlayKubeReport, error
logrus.Warn(err)
}
}()
- response, err := conn.DoRequest(ctx, f, http.MethodDelete, "/play/kube", nil, nil)
+
+ return KubeDownWithBody(ctx, f)
+}
+
+func KubeDownWithBody(ctx context.Context, body io.Reader) (*entities.PlayKubeReport, error) {
+ var report entities.PlayKubeReport
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := conn.DoRequest(ctx, body, http.MethodDelete, "/play/kube", nil, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 7cf7ca17f..6b70a3452 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -68,8 +68,8 @@ type ContainerEngine interface {
NetworkPrune(ctx context.Context, options NetworkPruneOptions) ([]*NetworkPruneReport, error)
NetworkReload(ctx context.Context, names []string, options NetworkReloadOptions) ([]*NetworkReloadReport, error)
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
- PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error)
- PlayKubeDown(ctx context.Context, path string, opts PlayKubeDownOptions) (*PlayKubeReport, error)
+ PlayKube(ctx context.Context, body io.Reader, opts PlayKubeOptions) (*PlayKubeReport, error)
+ PlayKubeDown(ctx context.Context, body io.Reader, opts PlayKubeDownOptions) (*PlayKubeReport, error)
PodCreate(ctx context.Context, specg PodSpec) (*PodCreateReport, error)
PodExists(ctx context.Context, nameOrID string) (*BoolReport, error)
PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 236d56053..1423ab06e 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -33,12 +33,12 @@ import (
yamlv2 "gopkg.in/yaml.v2"
)
-func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
report := &entities.PlayKubeReport{}
validKinds := 0
// read yaml document
- content, err := ioutil.ReadFile(path)
+ content, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}
@@ -52,7 +52,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
// sort kube kinds
documentList, err = sortKubeKinds(documentList)
if err != nil {
- return nil, errors.Wrapf(err, "unable to sort kube kinds in %q", path)
+ return nil, errors.Wrap(err, "unable to sort kube kinds")
}
ipIndex := 0
@@ -64,7 +64,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
for _, document := range documentList {
kind, err := getKubeKind(document)
if err != nil {
- return nil, errors.Wrapf(err, "unable to read %q as kube YAML", path)
+ return nil, errors.Wrap(err, "unable to read kube YAML")
}
switch kind {
@@ -73,7 +73,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var podTemplateSpec v1.PodTemplateSpec
if err := yaml.Unmarshal(document, &podYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Pod", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Pod")
}
podTemplateSpec.ObjectMeta = podYAML.ObjectMeta
@@ -97,7 +97,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var deploymentYAML v1apps.Deployment
if err := yaml.Unmarshal(document, &deploymentYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Deployment")
}
r, err := ic.playKubeDeployment(ctx, &deploymentYAML, options, &ipIndex, configMaps)
@@ -111,7 +111,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var pvcYAML v1.PersistentVolumeClaim
if err := yaml.Unmarshal(document, &pvcYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube PersistentVolumeClaim", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube PersistentVolumeClaim")
}
r, err := ic.playKubePVC(ctx, &pvcYAML, options)
@@ -125,7 +125,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var configMap v1.ConfigMap
if err := yaml.Unmarshal(document, &configMap); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube ConfigMap", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube ConfigMap")
}
configMaps = append(configMaps, configMap)
default:
@@ -773,14 +773,14 @@ func getBuildFile(imageName string, cwd string) (string, error) {
return "", err
}
-func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
+func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
var (
podNames []string
)
reports := new(entities.PlayKubeReport)
// read yaml document
- content, err := ioutil.ReadFile(path)
+ content, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}
@@ -794,27 +794,27 @@ func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ enti
// sort kube kinds
documentList, err = sortKubeKinds(documentList)
if err != nil {
- return nil, errors.Wrapf(err, "unable to sort kube kinds in %q", path)
+ return nil, errors.Wrap(err, "unable to sort kube kinds")
}
for _, document := range documentList {
kind, err := getKubeKind(document)
if err != nil {
- return nil, errors.Wrapf(err, "unable to read %q as kube YAML", path)
+ return nil, errors.Wrap(err, "unable to read as kube YAML")
}
switch kind {
case "Pod":
var podYAML v1.Pod
if err := yaml.Unmarshal(document, &podYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Pod", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Pod")
}
podNames = append(podNames, podYAML.ObjectMeta.Name)
case "Deployment":
var deploymentYAML v1apps.Deployment
if err := yaml.Unmarshal(document, &deploymentYAML); err != nil {
- return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path)
+ return nil, errors.Wrap(err, "unable to read YAML as Kube Deployment")
}
var numReplicas int32 = 1
deploymentName := deploymentYAML.ObjectMeta.Name
diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go
index cd51262d0..d9637254a 100644
--- a/pkg/domain/infra/tunnel/play.go
+++ b/pkg/domain/infra/tunnel/play.go
@@ -2,13 +2,14 @@ package tunnel
import (
"context"
+ "io"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/pkg/bindings/play"
"github.com/containers/podman/v4/pkg/domain/entities"
)
-func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
options := new(play.KubeOptions).WithAuthfile(opts.Authfile).WithUsername(opts.Username).WithPassword(opts.Password)
options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps)
options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Networks).WithSeccompProfileRoot(opts.SeccompProfileRoot)
@@ -26,9 +27,9 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entit
if start := opts.Start; start != types.OptionalBoolUndefined {
options.WithStart(start == types.OptionalBoolTrue)
}
- return play.Kube(ic.ClientCtx, path, options)
+ return play.KubeWithBody(ic.ClientCtx, body, options)
}
-func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
- return play.KubeDown(ic.ClientCtx, path)
+func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
+ return play.KubeDownWithBody(ic.ClientCtx, body)
}