Commit Graph

22 Commits

Author SHA1 Message Date
Matthew Arnold
cab586ab1a
Implement multi-stage ImageIO imports. (#1903)
* Add qemu-img rebase and commit operations.

Also only fail images with backing files that do not exist, so that
ImageIO snapshots can be downloaded and applied to a base disk image.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add merge phase to data processor.

This keeps qemu-img details out of the ImageIO data source.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Beef up transfer ticket finalization/cancellation.

Snapshots seem to be more prone to getting locked indefinitely than
disks if not correctly finalized or cancelled, so do this more carefully
than before.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Allow downloading snapshots from ImageIO.

Download the first snapshot as a raw whole-disk image, and download
subsequent snapshots as QCOW images to be committed to that base.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Allow multi-stage fields on ImageIO data sources.

Also avoid removing base disk image when cleaning data directory.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add ImageIO multi-stage functional tests.

Pick up fakeovirt update for stub functionality, so inventory responses
can be changed on the fly for individual tests.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Update multi-stage documentation for ImageIO.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Move if-else test block to functions.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Reset ImageIO inventory for a test I missed.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Clean up from some review comments.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Sort out calls to cleanupTransfer.

Failures during the creation of a transfer ticket call the original
cleanupTransfer in a single location, and any exits after the data
source is created call a wrapper function. The wrapper has a lock and a
'done' flag to make sure it is only called once on exit, even when
interrupted from the goroutine that waits for SIGTERM.

Signed-off-by: Matthew Arnold <marnold@redhat.com>
2021-08-30 19:22:07 +02:00
Arnon Gilboa
f1fb79bba0
Add DataSource as an optional sourceRef for DataVolumes (#1851)
* Add DataSource as an optional sourceRef for DataVolumes

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add some sourceRef validation unit and functional tests

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add cloner functional test for SourceRef PVC DataSource

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add test_ids

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Minor CR fixes

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add DV mutate utest

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>
2021-07-14 16:56:34 +02:00
Arnon Gilboa
13275ce351
OS image poll and update API (#1808)
* Add CRD for DataSource definition

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add optional sourceRef to DataSource in DataVolumeSpec

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add CRD for DataImportCron definition

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add DataSource and DataImportCron generated files

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Code review fixes

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* More code review fixes

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Code genrated after rebase

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Fix DV source reference in utests

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Remove api validation tests for missing data volume source

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>

* Add standard fields to condition structs

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>
2021-06-14 13:58:42 +02:00
akalenyu
0428dc5465
Stop using deprecated admissionregistration, apiregistration v1beta1 (#1804)
Switch admissionregistration.k8s.io/v1beta, apiregistration.k8s.io/v1beta1 to v1
as they are deprecated and will be removed from k8s-1.22.

apiextensions.k8s.io/v1beta1 was updated to v1 by https://github.com/kubevirt/containerized-data-importer/pull/1307.

Signed-off-by: Alex Kalenyuk <akalenyu@redhat.com>
2021-05-26 22:52:47 +02:00
Bartosz Rybacki
f81ab950fb
Use storage profiles when handling DataVolumes (#1753)
* Create new Storage type

A new Storage type similar to the PVC Spec is now available to use
in the DataVolume Spec. This is more permissive than PVC, and together
with StorageProfile this allows CDI to apply additional logic for
missing or optional fields.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Use the StorageProfile

Handle the StorageProfile recommended params when creating the PVC for
a DataVolume. When parameters like volumeMode or accessModes are
not provided, CDI checks the StorageProfile for a given StorageClass
to set the recommended defaults. This enables user to create DataVolume
without the need to provide all the parameters.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Allow multiple accessModes

CDI allows multiple access modes to be specified in the DataVolume.spec.storage and in the StorageProfile. This now works the same way as in PVC specification.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Handle the storage.size field

The storage.size specifies how much space a user wants to have.
When creating image on the fileSystem storage CDI takes into
account the file system overhead and requests PVC big enough to
fit an image and file system metadata.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Test storage profile with DV

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Document Storage Profiles

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Refactor: Render the effective PVC early

The helper 'render PVC' was moved earlier in the control flow, so
it can be used in more places. Removing the need for if/else logic.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Test handling size on import, upload and clone

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Code Review: Refactor resolving of volumeMode

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Fix: render target pvc spec correctly in smart clone controller

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>
2021-04-29 13:10:24 -05:00
Arnon Gilboa
6ff7537caa
Fix default content type validation for clone (#1659)
Signed-off-by: Arnon Gilboa <agilboa@redhat.com>
2021-02-18 00:01:01 +01:00
Arnon Gilboa
f7703a6bd7
Support cloning from Filesystem to Block and vice-versa (#1597)
* validate source and target pvcs has the same content type - for all clones
* if source and target volume modes are different, validate content type is kubevirt, and fallback to host-assisted cloning
* unit & func tests

Signed-off-by: Arnon Gilboa <agilboa@redhat.com>
2021-02-03 01:06:52 +01:00
Matthew Arnold
e54bc4c2fe
VDDK: incremental copy with changed block tracking (#1517)
* Plumb new checkpoint API through to VDDK importer.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add incremental data copy from VDDK.

Create a new data source implementation similar to vddk-datasource, but
only for blocks of data that changed between two snapshots. Also factor
out common things between the two VDDK data sources.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Check block status for warm and cold imports.

Addresses a bunch of runtime issues, but progress tracking isn't right.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Find snapshots correctly.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Remove separate warm/cold VDDK importers.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Advance through the checkpoint list in the spec.

Move DataVolume to Paused after each checkpoint, and start a new
importer pod for the next available checkpoint. Keep track of which
checkpoints have been copied by adding PVC annotations associating each
checkpoint with the UID of the pod that copied it.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Allow spec updates to drive multi-stage imports.

A multi-stage import can create checkpoints at any time, so CDI needs to
be able to receive updates to the list of checkpoints. Implement this by
allowing spec changes only for fields related to multi-stage imports.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Avoid deleting destination in multi-stage import.

A multi-stage import will have an initial data copy to the destination
file followed by separate copies for individual deltas. The destination
file should not be deleted before starting these delta copies.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Get VDDK data source to pass formatting tests.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Unit tests for multi-stage import admission rules.

Make sure only updates to checkpoint-related fields are accepted.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add warm import unit tests for VDDK data source.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add VDDK warm import functional test.

Put two snapshots in the vCenter simulator inventory, and run them
through a multi-stage import process.  Also clean up some issues
reported by test-lint.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add some documentation about multi-stage imports.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Pass existing multi-stage DataVolume unit tests.

Also remove MD5 sum step used for debugging, since it can take a long time.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Remove tabs from documentation.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Pass failing import-controller unit test.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* More unit tests for multi-stage field updates.

Also factor these tests into a DescribeTable.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add nbdkit retry filter.

Available as of Fedora 33 update.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Give correct file name to nbdkit in more cases.

The backing file in the spec might not always match the backing file in
the snapshot, so try harder to match those files by disk ID. May still
need to allow updates to backingFile, depending on how this gets used.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add more unit tests for datavolume-controller.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Fix linter error from last commit.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add unit tests for some govmomi API calls.

Move original calls into mock interfaces to make this work.

Signed-off-by: Matthew Arnold <marnold@redhat.com>
2020-12-18 15:58:47 +01:00
Marcelo Carneiro do Amaral
e9c2f84a00
Create a Datavolume if a coliding PVC with same name exists but is marked to delete (#1477)
* create DV if PVC is marked as deleted

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* tests/datavolume_test.go

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>
2020-12-02 18:12:39 +01:00
Maya Rashish
62325947ae
Update to k8s.io/klog/v2, used by kubernetes 1.19 (#1409)
Signed-off-by: Maya Rashish <mrashish@redhat.com>
2020-10-03 00:41:33 +02:00
Arnon Gilboa
35613d1cc6
Use semantic DeepEqual check on DV update (#1359)
Signed-off-by: Arnon Gilboa <agilboa@redhat.com>
2020-09-17 15:23:26 +02:00
Matthew Arnold
dc6bad6473
Fill out VDDK data volume source. (#1320)
* Add support for a VDDK datasource to the controllers

This commit does not implement the VDDK datasource. It simply
adds the DataVolumeSourceVDDK type and adds support to the
datavolume and import controllers for it. The datasource itself
will need to be done in a follow-up.

Signed-off-by: Sam Lucidi <slucidi@redhat.com>

* Fix tests and clean up lint

Signed-off-by: Sam Lucidi <slucidi@redhat.com>

* Add DataVolumeSourceVDDK to the v1alpha1 api group

Signed-off-by: Sam Lucidi <slucidi@redhat.com>

* Install nbdkit.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add govmomi to vendor directory.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Integrate govmomi into build.

Incomplete! This allows 'find' and 'object' imports from govmomi, but
further dependencies may require more bazel tweaks later.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Create a container image just to hold the VDDK.

Mount the VDDK folder to /opt. Also copy the libxcrypt-compat RPM to
/opt for run-time installation as a temporary workaround for my
inability to install it at container creation time. Make VDDK optional
by storing a dummy file in its directory, so an empty VDDK directory
will not break the build.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Fill in VDDK data source.

Add the simplest possible VDDK data source: set up an nbdkit server with
the given VMware parameters, and copy data out using qemu-img.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add vddk to resource validation schema.

Stops "error validating data" messages.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Move libxcrypt-compat install out of VDDK image.

Requiring users to add this to the VDDK image is kind of onerous, so
move it straight into the importer image instead.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Generate BUILD.bazel for the rest of govmomi.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Get VDDK sidecar image from v2v-vmware ConfigMap.

Convention from https://github.com/kubevirt/web-ui-components/pull/534

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Reduce nbdkit startup timeout.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Update govmomi dependencies.

Cleans up 'inconsistent vendoring' errors.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Fix schema verification test.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Change disk.raw to disk.img.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add vCenter simulator for VDDK datasource tests.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Functional test with vcsim and dummy VDDK plugin.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Clean up lint errors.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Check kubevirt-hyperconverged namespace for VDDK.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add VDDK unit tests and API functional test.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Read a raw image for VDDK test plugin.

Have the fake VDDK test plugin for nbdkit read a raw image passed in
/opt/updates/nbdtest.img instead of returning fixed data.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add some documentation about VDDK data sources.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Remove unit test focus and trailing spaces.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Use updated build container image.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add some extra comments about VDDK fields.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Clarify VDDK ConfigMap a little more.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Clarify namespace for vddk-init sidecar.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Remove NodePort from vCenter simulator manifest.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Re-word explanations on VDDK source types.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Add VDDK to comment with types needing URL check.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Rebuild types.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Move AnnThumbprint to storage.import.vddk.thumbprint.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Remove run-time installation of libxcrypt-compat.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Remove fixed namespaces for vddk-init reference.

The importer now looks for the v2v-vmware ConfigMap in the current CDI
namespace instead of openshift-cnv/kubevirt-hyperconverged.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

* Find CDI install namespace from data volume test.

Signed-off-by: Matthew Arnold <marnold@redhat.com>

Co-authored-by: Sam Lucidi <slucidi@redhat.com>
2020-09-11 23:37:22 +02:00
Michael Henriksen
75f4fd6f2f
update k8s deps to 18.6 and controller runtime to 0.6.2 (#1330)
* update k8s deps to 1.18.6 and controller runtime to 0.6.2

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* remove building code generators from docker image.  This way the k8s ligray version only has to be updated in go.mod

Do more stuff in the bazel container.  Faster and better interop

Fix unit tests

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* make format

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* remove unnecessary rsync

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* redo code generator dep management

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* builder uses go modules

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>
2020-08-07 14:09:52 +02:00
Alexander Wels
6dce12f090
Move CRDS from apiextensions v1beta1 to v1. (#1307)
* Move CRDS from apiextensions v1beta1 to v1.
Ensure that our code based schema validation matches the types in the api.

Signed-off-by: Alexander Wels <awels@redhat.com>

* Ran go mod tidy and vendor in attempt to see if we could use newer runtime controller, but our go version too old.
Addressed review comments.

Signed-off-by: Alexander Wels <awels@redhat.com>

* Addressed more review comments and fixed k8s-1.18 functional test failing.

Signed-off-by: Alexander Wels <awels@redhat.com>

* Remove categories 'all' from cluster scoped CRDs

Signed-off-by: Alexander Wels <awels@redhat.com>
2020-08-01 01:01:50 +02:00
Michael Henriksen
9e2c79b1e0
move api groups to v1beta1 (#1232)
* move upload.cdi.kubevirt.io API group to v1beta1

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* move core api to v1beta1

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* fix os-3.11 cluster sync and add functional tests for alpha api

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* change more occurences of v1alpha1

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>

* updates after rebase

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>
2020-07-10 15:47:38 +02:00
Bartosz Rybacki
ab8b9c025e
Generating label names (#1200)
* Handle labels length correctly

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Handle service name generation correctly

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Remove not needed labels

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Store import pod name in annotation

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Enable long DV name

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Handle name with dot when creating service/label name

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Test long names on import,  upload and clone

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Store upload pod name in annotation

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Store importer scratch pvc name in annotation

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Quick fix for tests (need improvements)

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Cleanup handling scratch name

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Ensure pod/service name conflicts are handled

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Handle client errors when trying to get the import pod

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Style improvements, and other code review fixes.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Store clone source pod name in an annotation

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Correct name initialization and tests

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Do not init name if pod already exists. It is not needed.

The situation of having a pod but not name on annotation can happen after the upgrade, when we have a legacy pvc and pod already existing, but clone operation not finished. But when we already have the pod, then in the code (currently) we do not need the name from annotation.

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Cleanup scratch name handling

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Use constant for max dv name in validation

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>

* Simplify clone source pod name initialization

Signed-off-by: Bartosz Rybacki <brybacki@redhat.com>
2020-05-29 19:55:32 +02:00
Michael Henriksen
487a60d632
Allow for "pre initialized" DataVolumes. (#1183)
These are basically no-op DataVolumes for PVCs that already exist.

I see this mostly as an internal thing to facilitate VM restore from snapshot

Signed-off-by: Michael Henriksen <mhenriks@redhat.com>
2020-04-17 14:58:03 +02:00
Piotr Kliczewski
78cee6d166
Imageio - new import data source (#1042)
This PR introduces new import data source to fetch disks from ovirt
and store them in storage available in the cluster. It uses ovirt-sdk
to check whether the this is there, the size of the disk and it obtains
signed ticket which allows to get the disk using ovirt-imageio-proxy.

In order to use it a user needs to create configmap with ovirt api
certificate and secret with ovirt engine user and password. Both are
required and validated by webhook. In order to start import process
we need to post following definition:

---
apiVersion: cdi.kubevirt.io/v1alpha1
kind: DataVolume
metadata:
  name: "imageio-dv"
spec:
  source:
      imageio:
         url: "<engine-api-endpoint>"
         secretRef: "<secret-name-containing-engine-credentials>"
         certConfigMap: "<configmap-name-containing-engine-api-certificate>"
         diskId: "<disk-id-which-we-want-to-import>"
  pvc:
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: "64Mi"
---

Signed-off-by: Piotr Kliczewski <piotr.kliczewski@gmail.com>
2020-03-19 19:49:44 +01:00
Alexander Wels
1c4918eb8c
Fix up the validation of sources logic to be easier to understand and extend. (#1128)
Signed-off-by: Alexander Wels <awels@redhat.com>
2020-02-28 20:36:53 +01:00
Michael Henriksen
e4fa647eea Clone permission refactoring (#906)
* allow user with 'create pod' permission in source namespace to clone PVCs also refactored Kubevirt interface to clone permission check

* make sure DataVolume spec is immutable also don't check perms when clone source namespace = dest namespace
2019-08-05 11:04:03 -04:00
zvikorn
e96ed9f753 Adding webhook validation for length of DataVolume name (#903)
Signed-off-by: tavni <tavni@redhat.com>
2019-08-01 16:04:04 -04:00
Michael Henriksen
ec52c85a25 Validating webhook and token authorization for PVC cloning (#869)
* baseline refactoring of webhook package

* datavolume clone validation webhook

* rename datavolumes/clone-init to datavolumes/source

* add RBAC doc

* updates from review

* make clone permission check exportable function

* force dumb cloning in in functional test
2019-07-09 14:02:31 -04:00