diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/compat/containers_logs.go | 4 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/play.go | 44 | ||||
-rw-r--r-- | pkg/api/server/register_play.go | 15 | ||||
-rw-r--r-- | pkg/bindings/play/play.go | 29 | ||||
-rw-r--r-- | pkg/bindings/play/types.go | 4 | ||||
-rw-r--r-- | pkg/domain/entities/engine_container.go | 1 | ||||
-rw-r--r-- | pkg/domain/entities/play.go | 13 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 70 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/play.go | 4 | ||||
-rw-r--r-- | pkg/machine/fcos.go | 4 | ||||
-rw-r--r-- | pkg/machine/fcos_amd64.go | 14 | ||||
-rw-r--r-- | pkg/machine/fcos_arm64.go | 2 | ||||
-rw-r--r-- | pkg/machine/qemu/machine.go | 24 | ||||
-rw-r--r-- | pkg/util/utils.go | 7 | ||||
-rw-r--r-- | pkg/util/utils_test.go | 2 |
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) } |