summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_logs.go4
-rw-r--r--pkg/api/handlers/libpod/play.go44
-rw-r--r--pkg/api/server/register_play.go15
-rw-r--r--pkg/bindings/play/play.go29
-rw-r--r--pkg/bindings/play/types.go4
-rw-r--r--pkg/domain/entities/engine_container.go1
-rw-r--r--pkg/domain/entities/play.go13
-rw-r--r--pkg/domain/infra/abi/play.go70
-rw-r--r--pkg/domain/infra/tunnel/play.go4
-rw-r--r--pkg/machine/fcos.go4
-rw-r--r--pkg/machine/fcos_amd64.go14
-rw-r--r--pkg/machine/fcos_arm64.go2
-rw-r--r--pkg/machine/qemu/machine.go24
-rw-r--r--pkg/util/utils.go7
-rw-r--r--pkg/util/utils_test.go2
15 files changed, 211 insertions, 26 deletions
diff --git a/pkg/api/handlers/compat/containers_logs.go b/pkg/api/handlers/compat/containers_logs.go
index 0c10ce75e..a7cfe09ea 100644
--- a/pkg/api/handlers/compat/containers_logs.go
+++ b/pkg/api/handlers/compat/containers_logs.go
@@ -63,7 +63,7 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
var since time.Time
if _, found := r.URL.Query()["since"]; found {
- since, err = util.ParseInputTime(query.Since)
+ since, err = util.ParseInputTime(query.Since, true)
if err != nil {
utils.BadRequest(w, "since", query.Since, err)
return
@@ -73,7 +73,7 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
var until time.Time
if _, found := r.URL.Query()["until"]; found {
if query.Until != "0" {
- until, err = util.ParseInputTime(query.Until)
+ until, err = util.ParseInputTime(query.Until, false)
if err != nil {
utils.BadRequest(w, "until", query.Until, err)
return
diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go
index 90332924c..4f79d5f20 100644
--- a/pkg/api/handlers/libpod/play.go
+++ b/pkg/api/handlers/libpod/play.go
@@ -15,6 +15,7 @@ import (
"github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/gorilla/schema"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
func PlayKube(w http.ResponseWriter, r *http.Request) {
@@ -66,9 +67,15 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
return
}
- defer os.Remove(tmpfile.Name())
+ 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 {
- tmpfile.Close()
+ if err := tmpfile.Close(); err != nil {
+ logrus.Warn(err)
+ }
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
return
}
@@ -105,12 +112,43 @@ 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)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error playing YAML file"))
return
}
+ utils.WriteResponse(w, http.StatusOK, report)
+}
+func PlayKubeDown(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
+ if err != nil {
+ utils.Error(w, "Something went wrong.", 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, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
+ return
+ }
+ if err := tmpfile.Close(); err != nil {
+ utils.Error(w, "Something went wrong.", 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)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error tearing down YAML file"))
+ return
+ }
utils.WriteResponse(w, http.StatusOK, report)
}
diff --git a/pkg/api/server/register_play.go b/pkg/api/server/register_play.go
index c51301aa8..915d0d02e 100644
--- a/pkg/api/server/register_play.go
+++ b/pkg/api/server/register_play.go
@@ -59,5 +59,20 @@ func (s *APIServer) registerPlayHandlers(r *mux.Router) error {
// 500:
// $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/play/kube"), s.APIHandler(libpod.PlayKube)).Methods(http.MethodPost)
+ // swagger:operation DELETE /libpod/play/kube libpod PlayKubeDownLibpod
+ // ---
+ // tags:
+ // - containers
+ // - pods
+ // summary: Remove pods from play kube
+ // description: Tears down pods defined in a YAML file
+ // produces:
+ // - application/json
+ // responses:
+ // 200:
+ // $ref: "#/responses/DocsLibpodPlayKubeResponse"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/play/kube"), s.APIHandler(libpod.PlayKubeDown)).Methods(http.MethodDelete)
return nil
}
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index 8451cd533..89a6f9b65 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -6,6 +6,8 @@ import (
"os"
"strconv"
+ "github.com/sirupsen/logrus"
+
"github.com/containers/podman/v3/pkg/auth"
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/domain/entities"
@@ -56,3 +58,30 @@ func Kube(ctx context.Context, path string, options *KubeOptions) (*entities.Pla
return &report, nil
}
+
+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
+ }
+ defer func() {
+ if err := f.Close(); err != nil {
+ logrus.Warn(err)
+ }
+ }()
+ response, err := conn.DoRequest(f, http.MethodDelete, "/play/kube", nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ if err := response.Process(&report); err != nil {
+ return nil, err
+ }
+
+ return &report, nil
+}
diff --git a/pkg/bindings/play/types.go b/pkg/bindings/play/types.go
index 52a72c7b6..787069169 100644
--- a/pkg/bindings/play/types.go
+++ b/pkg/bindings/play/types.go
@@ -1,6 +1,8 @@
package play
-import "net"
+import (
+ "net"
+)
//go:generate go run ../generator/generator.go KubeOptions
// KubeOptions are optional options for replaying kube YAML files
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 5d3c9480e..5acf7211c 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -67,6 +67,7 @@ type ContainerEngine interface {
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)
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
PodExists(ctx context.Context, nameOrID string) (*BoolReport, error)
PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go
index 01de73ebe..77329e328 100644
--- a/pkg/domain/entities/play.go
+++ b/pkg/domain/entities/play.go
@@ -14,6 +14,9 @@ type PlayKubeOptions struct {
Build bool
// CertDir - to a directory containing TLS certifications and keys.
CertDir string
+ // Down indicates whether to bring contents of a yaml file "down"
+ // as in stop
+ Down bool
// Username for authenticating against the registry.
Username string
// Password for authenticating against the registry.
@@ -67,4 +70,14 @@ type PlayKubeReport struct {
Pods []PlayKubePod
// Volumes - volumes created by play kube.
Volumes []PlayKubeVolume
+ PlayKubeTeardown
+}
+
+// PlayKubeDownOptions are options for tearing down pods
+type PlayKubeDownOptions struct{}
+
+// PlayKubeDownReport contains the results of tearing down play kube
+type PlayKubeTeardown struct {
+ StopReport []*PodStopReport
+ RmReport []*PodRmReport
}
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 6224feff5..f22b2dbbb 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -586,3 +586,73 @@ func getBuildFile(imageName string, cwd string) (string, error) {
}
return "", err
}
+
+func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
+ var (
+ podNames []string
+ )
+ reports := new(entities.PlayKubeReport)
+
+ // read yaml document
+ content, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+
+ // split yaml document
+ documentList, err := splitMultiDocYAML(content)
+ if err != nil {
+ return nil, err
+ }
+
+ // sort kube kinds
+ documentList, err = sortKubeKinds(documentList)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to sort kube kinds in %q", path)
+ }
+
+ for _, document := range documentList {
+ kind, err := getKubeKind(document)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to read %q as kube YAML", path)
+ }
+
+ 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)
+ }
+ 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)
+ }
+ var numReplicas int32 = 1
+ deploymentName := deploymentYAML.ObjectMeta.Name
+ if deploymentYAML.Spec.Replicas != nil {
+ numReplicas = *deploymentYAML.Spec.Replicas
+ }
+ for i := 0; i < int(numReplicas); i++ {
+ podName := fmt.Sprintf("%s-pod-%d", deploymentName, i)
+ podNames = append(podNames, podName)
+ }
+ default:
+ continue
+ }
+ }
+
+ // Add the reports
+ reports.StopReport, err = ic.PodStop(ctx, podNames, entities.PodStopOptions{})
+ if err != nil {
+ return nil, err
+ }
+
+ reports.RmReport, err = ic.PodRm(ctx, podNames, entities.PodRmOptions{})
+ if err != nil {
+ return nil, err
+ }
+ return reports, nil
+}
diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go
index e66ff0308..e39751a18 100644
--- a/pkg/domain/infra/tunnel/play.go
+++ b/pkg/domain/infra/tunnel/play.go
@@ -22,3 +22,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entit
}
return play.Kube(ic.ClientCtx, path, options)
}
+
+func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) {
+ return play.KubeDown(ic.ClientCtx, path)
+}
diff --git a/pkg/machine/fcos.go b/pkg/machine/fcos.go
index 49ec01e67..85cedcd5a 100644
--- a/pkg/machine/fcos.go
+++ b/pkg/machine/fcos.go
@@ -24,8 +24,8 @@ type FcosDownload struct {
Download
}
-func NewFcosDownloader(vmType, vmName string) (DistributionDownload, error) {
- info, err := getFCOSDownload()
+func NewFcosDownloader(vmType, vmName, imageStream string) (DistributionDownload, error) {
+ info, err := getFCOSDownload(imageStream)
if err != nil {
return nil, err
}
diff --git a/pkg/machine/fcos_amd64.go b/pkg/machine/fcos_amd64.go
index 36676405a..4e2e86d3e 100644
--- a/pkg/machine/fcos_amd64.go
+++ b/pkg/machine/fcos_amd64.go
@@ -8,16 +8,26 @@ import (
"github.com/coreos/stream-metadata-go/fedoracoreos"
"github.com/coreos/stream-metadata-go/stream"
+ "github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
// This should get Exported and stay put as it will apply to all fcos downloads
// getFCOS parses fedoraCoreOS's stream and returns the image download URL and the release version
-func getFCOSDownload() (*fcosDownloadInfo, error) {
+func getFCOSDownload(imageStream string) (*fcosDownloadInfo, error) {
var (
fcosstable stream.Stream
+ streamType string
)
- streamurl := fedoracoreos.GetStreamURL(fedoracoreos.StreamNext)
+ switch imageStream {
+ case "testing", "":
+ streamType = fedoracoreos.StreamNext
+ case "stable":
+ streamType = fedoracoreos.StreamStable
+ default:
+ return nil, errors.Errorf("invalid stream %s: valid streams are `testing` and `stable`", imageStream)
+ }
+ streamurl := fedoracoreos.GetStreamURL(streamType)
resp, err := http.Get(streamurl.String())
if err != nil {
return nil, err
diff --git a/pkg/machine/fcos_arm64.go b/pkg/machine/fcos_arm64.go
index f5cd5a505..f45522be0 100644
--- a/pkg/machine/fcos_arm64.go
+++ b/pkg/machine/fcos_arm64.go
@@ -13,7 +13,7 @@ const aarchBaseURL = "https://fedorapeople.org/groups/fcos-images/builds/latest/
// Total hack until automation is possible.
// We need a proper json file at least to automate
-func getFCOSDownload() (*fcosDownloadInfo, error) {
+func getFCOSDownload(imageStream string) (*fcosDownloadInfo, error) {
meta := Build{}
resp, err := http.Get(aarchBaseURL + "meta.json")
if err != nil {
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index a92892957..871436618 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -138,29 +138,29 @@ func (v *MachineVM) Init(opts machine.InitOptions) error {
jsonFile := filepath.Join(vmConfigDir, v.Name) + ".json"
v.IdentityPath = filepath.Join(sshDir, v.Name)
- // The user has provided an alternate image which can be a file path
- // or URL.
- if len(opts.ImagePath) > 0 {
- g, err := machine.NewGenericDownloader(vmtype, v.Name, opts.ImagePath)
+ switch opts.ImagePath {
+ case "testing", "stable", "":
+ // Get image as usual
+ dd, err := machine.NewFcosDownloader(vmtype, v.Name, opts.ImagePath)
if err != nil {
return err
}
- v.ImagePath = g.Get().LocalUncompressedFile
- if err := g.DownloadImage(); err != nil {
+ v.ImagePath = dd.Get().LocalUncompressedFile
+ if err := dd.DownloadImage(); err != nil {
return err
}
- } else {
- // Get the image as usual
- dd, err := machine.NewFcosDownloader(vmtype, v.Name)
+ default:
+ // The user has provided an alternate image which can be a file path
+ // or URL.
+ g, err := machine.NewGenericDownloader(vmtype, v.Name, opts.ImagePath)
if err != nil {
return err
}
- v.ImagePath = dd.Get().LocalUncompressedFile
- if err := dd.DownloadImage(); err != nil {
+ v.ImagePath = g.Get().LocalUncompressedFile
+ if err := g.DownloadImage(); err != nil {
return err
}
}
-
// Add arch specific options including image location
v.CmdLine = append(v.CmdLine, v.addArchOptions()...)
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 63fad0286..208d815d9 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -520,7 +520,7 @@ func WriteStorageConfigFile(storageOpts *stypes.StoreOptions, storageConf string
// ParseInputTime takes the users input and to determine if it is valid and
// returns a time format and error. The input is compared to known time formats
// or a duration which implies no-duration
-func ParseInputTime(inputTime string) (time.Time, error) {
+func ParseInputTime(inputTime string, since bool) (time.Time, error) {
timeFormats := []string{time.RFC3339Nano, time.RFC3339, "2006-01-02T15:04:05", "2006-01-02T15:04:05.999999999",
"2006-01-02Z07:00", "2006-01-02"}
// iterate the supported time formats
@@ -542,7 +542,10 @@ func ParseInputTime(inputTime string) (time.Time, error) {
if err != nil {
return time.Time{}, errors.Errorf("unable to interpret time value")
}
- return time.Now().Add(-duration), nil
+ if since {
+ return time.Now().Add(-duration), nil
+ }
+ return time.Now().Add(duration), nil
}
// OpenExclusiveFile opens a file for writing and ensure it doesn't already exist
diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go
index 62de7509f..3d74d4c78 100644
--- a/pkg/util/utils_test.go
+++ b/pkg/util/utils_test.go
@@ -303,7 +303,7 @@ func TestPeriodAndQuotaToCores(t *testing.T) {
}
func TestParseInputTime(t *testing.T) {
- tm, err := ParseInputTime("1.5")
+ tm, err := ParseInputTime("1.5", true)
if err != nil {
t.Errorf("expected error to be nil but was: %v", err)
}