Merge pull request #13606 from paralin/play-kube-inmem

play: kube: support io.reader body arg and remove tempfiles
This commit is contained in:
OpenShift Merge Robot
2022-03-24 12:41:28 +01:00
committed by GitHub
6 changed files with 65 additions and 88 deletions

View File

@ -209,10 +209,15 @@ func teardown(yamlfile string) error {
podRmErrors utils.OutputErrors podRmErrors utils.OutputErrors
) )
options := new(entities.PlayKubeDownOptions) options := new(entities.PlayKubeDownOptions)
reports, err := registry.ContainerEngine().PlayKubeDown(registry.GetContext(), yamlfile, *options) f, err := os.Open(yamlfile)
if err != nil { if err != nil {
return err return err
} }
defer f.Close()
reports, err := registry.ContainerEngine().PlayKubeDown(registry.GetContext(), f, *options)
if err != nil {
return errors.Wrap(err, yamlfile)
}
// Output stopped pods // Output stopped pods
fmt.Println("Pods stopped:") fmt.Println("Pods stopped:")
@ -242,10 +247,15 @@ func teardown(yamlfile string) error {
} }
func playkube(yamlfile string) error { func playkube(yamlfile string) error {
report, err := registry.ContainerEngine().PlayKube(registry.GetContext(), yamlfile, kubeOptions.PlayKubeOptions) f, err := os.Open(yamlfile)
if err != nil { if err != nil {
return err return err
} }
defer f.Close()
report, err := registry.ContainerEngine().PlayKube(registry.GetContext(), f, kubeOptions.PlayKubeOptions)
if err != nil {
return errors.Wrap(err, yamlfile)
}
// Print volumes report // Print volumes report
for i, volume := range report.Volumes { for i, volume := range report.Volumes {
if i == 0 { if i == 0 {

View File

@ -1,11 +1,8 @@
package libpod package libpod
import ( import (
"io"
"io/ioutil"
"net" "net"
"net/http" "net/http"
"os"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod"
@ -16,7 +13,6 @@ import (
"github.com/containers/podman/v4/pkg/domain/infra/abi" "github.com/containers/podman/v4/pkg/domain/infra/abi"
"github.com/gorilla/schema" "github.com/gorilla/schema"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
) )
func PlayKube(w http.ResponseWriter, r *http.Request) { func PlayKube(w http.ResponseWriter, r *http.Request) {
@ -62,28 +58,6 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
staticMACs = append(staticMACs, mac) 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) authConf, authfile, err := auth.GetCredentials(r)
if err != nil { if err != nil {
utils.Error(w, http.StatusBadRequest, err) 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 { if _, found := r.URL.Query()["start"]; found {
options.Start = types.NewOptionalBool(query.Start) 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 { if err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error playing YAML file")) utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error playing YAML file"))
return return
@ -126,30 +101,10 @@ 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(api.RuntimeKey).(*libpod.Runtime) 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} containerEngine := abi.ContainerEngine{Libpod: runtime}
options := new(entities.PlayKubeDownOptions) 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 { if err != nil {
utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error tearing down YAML file")) utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "error tearing down YAML file"))
return return

View File

@ -2,6 +2,7 @@ package play
import ( import (
"context" "context"
"io"
"net/http" "net/http"
"os" "os"
"strconv" "strconv"
@ -14,21 +15,26 @@ import (
) )
func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.PlayKubeReport, error) { func Kube(ctx context.Context, path string, 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) f, err := os.Open(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer f.Close() 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
}
params, err := options.ToParams() params, err := options.ToParams()
if err != nil { if err != nil {
return nil, err return nil, err
@ -46,7 +52,7 @@ func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.Pla
return nil, err 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 { if err != nil {
return nil, err 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) { 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) f, err := os.Open(path)
if err != nil { if err != nil {
return nil, err return nil, err
@ -75,7 +75,18 @@ func KubeDown(ctx context.Context, path string) (*entities.PlayKubeReport, error
logrus.Warn(err) 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -68,8 +68,8 @@ type ContainerEngine interface {
NetworkPrune(ctx context.Context, options NetworkPruneOptions) ([]*NetworkPruneReport, error) NetworkPrune(ctx context.Context, options NetworkPruneOptions) ([]*NetworkPruneReport, error)
NetworkReload(ctx context.Context, names []string, options NetworkReloadOptions) ([]*NetworkReloadReport, error) NetworkReload(ctx context.Context, names []string, options NetworkReloadOptions) ([]*NetworkReloadReport, error)
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error) NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error) PlayKube(ctx context.Context, body io.Reader, opts PlayKubeOptions) (*PlayKubeReport, error)
PlayKubeDown(ctx context.Context, path string, opts PlayKubeDownOptions) (*PlayKubeReport, error) PlayKubeDown(ctx context.Context, body io.Reader, opts PlayKubeDownOptions) (*PlayKubeReport, error)
PodCreate(ctx context.Context, specg PodSpec) (*PodCreateReport, error) PodCreate(ctx context.Context, specg PodSpec) (*PodCreateReport, error)
PodExists(ctx context.Context, nameOrID string) (*BoolReport, error) PodExists(ctx context.Context, nameOrID string) (*BoolReport, error)
PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error) PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)

View File

@ -33,12 +33,12 @@ import (
yamlv2 "gopkg.in/yaml.v2" 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{} report := &entities.PlayKubeReport{}
validKinds := 0 validKinds := 0
// read yaml document // read yaml document
content, err := ioutil.ReadFile(path) content, err := ioutil.ReadAll(body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -52,7 +52,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
// sort kube kinds // sort kube kinds
documentList, err = sortKubeKinds(documentList) documentList, err = sortKubeKinds(documentList)
if err != nil { 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 ipIndex := 0
@ -64,7 +64,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
for _, document := range documentList { for _, document := range documentList {
kind, err := getKubeKind(document) kind, err := getKubeKind(document)
if err != nil { 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 { switch kind {
@ -73,7 +73,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var podTemplateSpec v1.PodTemplateSpec var podTemplateSpec v1.PodTemplateSpec
if err := yaml.Unmarshal(document, &podYAML); err != nil { 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 podTemplateSpec.ObjectMeta = podYAML.ObjectMeta
@ -97,7 +97,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
var deploymentYAML v1apps.Deployment var deploymentYAML v1apps.Deployment
if err := yaml.Unmarshal(document, &deploymentYAML); err != nil { 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) 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 var pvcYAML v1.PersistentVolumeClaim
if err := yaml.Unmarshal(document, &pvcYAML); err != nil { 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) 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 var configMap v1.ConfigMap
if err := yaml.Unmarshal(document, &configMap); err != nil { 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) configMaps = append(configMaps, configMap)
default: default:
@ -773,14 +773,14 @@ func getBuildFile(imageName string, cwd string) (string, error) {
return "", err 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 ( var (
podNames []string podNames []string
) )
reports := new(entities.PlayKubeReport) reports := new(entities.PlayKubeReport)
// read yaml document // read yaml document
content, err := ioutil.ReadFile(path) content, err := ioutil.ReadAll(body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -794,27 +794,27 @@ func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ enti
// sort kube kinds // sort kube kinds
documentList, err = sortKubeKinds(documentList) documentList, err = sortKubeKinds(documentList)
if err != nil { 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 { for _, document := range documentList {
kind, err := getKubeKind(document) kind, err := getKubeKind(document)
if err != nil { 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 { switch kind {
case "Pod": case "Pod":
var podYAML v1.Pod var podYAML v1.Pod
if err := yaml.Unmarshal(document, &podYAML); err != nil { 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) podNames = append(podNames, podYAML.ObjectMeta.Name)
case "Deployment": case "Deployment":
var deploymentYAML v1apps.Deployment var deploymentYAML v1apps.Deployment
if err := yaml.Unmarshal(document, &deploymentYAML); err != nil { 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 var numReplicas int32 = 1
deploymentName := deploymentYAML.ObjectMeta.Name deploymentName := deploymentYAML.ObjectMeta.Name

View File

@ -2,13 +2,14 @@ package tunnel
import ( import (
"context" "context"
"io"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/containers/podman/v4/pkg/bindings/play" "github.com/containers/podman/v4/pkg/bindings/play"
"github.com/containers/podman/v4/pkg/domain/entities" "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 := 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.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps)
options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Networks).WithSeccompProfileRoot(opts.SeccompProfileRoot) 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 { if start := opts.Start; start != types.OptionalBoolUndefined {
options.WithStart(start == types.OptionalBoolTrue) 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) { func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
return play.KubeDown(ic.ClientCtx, path) return play.KubeDownWithBody(ic.ClientCtx, body)
} }