Commit Graph

7834 Commits

Author SHA1 Message Date
Eric Blake
89d994ad6b build: update gnulib for intprops
Done as a separate commit to make backporting the next patch easier.
We are already using "intprops.h", but this makes it explicit.

* .gnulib: Update, for syntax-check fix.
* bootstrap.conf (gnulib_modules): Make intprops use explicit.
* src/locking/domain_lock.c (includes): Drop unused header.
* src/nwfilter/nwfilter_learnipaddr.c (includes): Use "", not <>,
for gnulib.
2011-06-24 15:52:52 -06:00
Eric Blake
2abb4616a0 build: avoid long line tests
'make syntax-check' regression introduced in commit 60b9c69.

* tests/networkxml2argvdata/*.argv: Break long lines.
2011-06-24 15:34:28 -06:00
Matthias Bolte
d95f673ad2 Rename iface(G|S)etMacaddr to iface(G|S)etMacAddress for consistency 2011-06-24 23:06:56 +02:00
Matthias Bolte
a800d66b72 Fix typo in libvirt_private.syms
Triggered a linker error on MinGW.
2011-06-24 22:39:48 +02:00
Michal Novotny
9d4e2845d4 Network: Add support for DNS hosts definition to the network XML
This commit introduces names definition for the DNS hosts file using
the following syntax:

  <dns>
    <host ip="192.168.1.1">
      <name>alias1</name>
      <name>alias2</name>
    </host>
  </dns>

Some of the improvements and fixes were done by Laine Stump so
I'm putting him into the SOB clause again ;-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
Signed-off-by: Laine Stump <laine@laine.org>
2011-06-24 16:15:36 -04:00
Michal Novotny
91b7924eee Network: Add additional hosts internal infrastructure
Signed-off-by: Michal Novotny <minovotn@redhat.com>
2011-06-24 16:15:33 -04:00
Michal Novotny
60b9c69313 Network: Add regression tests for the command-line arguments
The regression testing done by comparison of command-line
generated from the network XML file and the expected
command-line arguments (read from file).

Signed-off-by: Michal Novotny <minovotn@redhat.com>
2011-06-24 16:15:27 -04:00
Michal Novotny
89ae9849f7 Network: modify dnsmasq commandline build function to allow testing
The dnsmasq commandline was being built as a part of running
dnsmasq. This patch puts the commandline build into a separate
function (and exports it as a private API) making it possible to build
a dnsmasq commandline without executing it, so that we can write a
test program to verify that the proper commandlines are being created.

Signed-off-by: Michal Novotny <minovotn@redhat.com>
2011-06-24 16:15:17 -04:00
Michal Novotny
5dd986dbd7 Add TXT record support for virtual DNS service
This commit introduces the <dns> element and <txt> record for the
virtual DNS network. The DNS TXT record can be defined using following
syntax in the network XML file:

  <dns>
    <txt name="example" value="example value" />
  </dns>

Also, the Relax-NG scheme has been altered to allow the texts without
spaces only for the name element and some nitpicks about memory
free'ing have been fixed by Laine so therefore I'm adding Laine to the
SOB clause ;-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
Signed-off-by: Laine Stump <laine@laine.org>
2011-06-24 16:15:12 -04:00
Matthias Bolte
9a48ed54f8 python: Don't declare Py_ssize_t for Python 2.6
Commit cd48c3f4e9 added a Py_ssize_t typedef for Python < 2.7.
But Py_ssize_t was added in Python 2.5. This makes the build fail
for Python 2.6.

Adjust the check to match Python < 2.5 to fix this.
2011-06-24 19:34:56 +02:00
Matthias Bolte
d772167f6d tests: Improve IPv6 detection for virNetSocket tests
getifaddrs can return an IPv6 address, but getaddrinfo can fail
for an IPv6 address. Cover this combination.
2011-06-24 18:46:06 +02:00
Jamie Strandboge
0b501bd4e1 Move load of AppArmor profile to GenLabel()
Commit 12317957ec introduced an incompatible
architectural change for the AppArmor security driver. Specifically,
virSecurityManagerSetAllLabel() is now called much later in
src/qemu/qemu_process.c:qemuProcessStart(). Previously, SetAllLabel() was
called immediately after GenLabel() such that after the dynamic label (profile
name) was generated, SetAllLabel() would be called to create and load the
AppArmor profile into the kernel before qemuProcessHook() was executed. With
12317957ec, qemuProcessHook() is now called
before SetAllLabel(), such that aa_change_profile() ends up being called
before the AppArmor profile is loaded into the kernel (via ProcessLabel() in
qemuProcessHook()).

This patch addresses the change by making GenLabel() load the AppArmor
profile into the kernel after the label (profile name) is generated.
SetAllLabel() is then adjusted to only reload_profile() and append stdin_fn to
the profile when it is specified. This also makes the AppArmor driver work
like its SELinux counterpart with regard to SetAllLabel() and stdin_fn.
Bug-Ubuntu: https://launchpad.net/bugs/801569
2011-06-24 10:09:44 -06:00
Eric Blake
db323e3b97 docs: document correct flag name
When adding virDomainGetVcpusFlags in commit ea3f5c6, I did
enough rebasing that the doc comments in libvirt.c no longer
matched the final chosen enum names in libvirt.h.

And now we've gone ahead and deprecated the names
VIR_DOMAIN_VCPU_{LIVE,CONFIG}.

* src/libvirt.c (virDomainGetVcpusFlags): Fix comment.
2011-06-24 09:04:49 -06:00
Eric Blake
1aa859d633 Revert "Add new API virDomainBlockPull* to headers"
This reverts commit 7d56a16d03.

Conflicts:

	python/generator.py
	src/libvirt_public.syms
2011-06-24 08:41:25 -06:00
Eric Blake
6389bea91c Revert "virDomainBlockPull: Implement the main entry points"
This reverts commit 6419f596e1.
2011-06-24 08:41:25 -06:00
Eric Blake
9872323623 Revert "Add virDomainBlockPull support to the remote driver"
This reverts commit d1693bb160.

Conflicts:

	daemon/remote.c
	src/remote/remote_driver.c
	src/remote/remote_protocol.x
2011-06-24 08:41:25 -06:00
Eric Blake
3c2f0a17e2 Revert "Implement virDomainBlockPull for the qemu driver"
This reverts commit 784ee08d22.
2011-06-24 08:41:25 -06:00
Eric Blake
f7f5e3e806 Revert "Enable the virDomainBlockPull API in virsh"
This reverts commit 3e2493ce28.
2011-06-24 08:41:24 -06:00
Eric Blake
21ecea2e93 Revert "Enable virDomainBlockPull in the python API."
This reverts commit d74b86f5d6.

Conflicts:

	python/generator.py
2011-06-24 08:41:24 -06:00
Eric Blake
c4c59e7228 Revert "Asynchronous event for BlockPull completion"
This reverts commit 12cd77a0c5.

Conflicts:

	python/libvirt-override-virConnect.py
	python/libvirt-override.c
	src/remote/remote_protocol.x
2011-06-24 08:41:24 -06:00
Eric Blake
cd48c3f4e9 build: avoid python 2.4 build failure
I'm not sure when Py_ssize_t was introduced; but Fedora 14 Python 2.7
has it, while RHEL 5 Python 2.4 lacks it.  It should be easy enough
to adjust if someone runs into problems.

* python/typewrappers.h (Py_ssize_t): Define for older python.
2011-06-24 08:28:56 -06:00
Eric Blake
98d83094a0 build: fix NUMA build on RHEL 5
Use NUMA's older nodemask_t (fixed-size map) rather than the newer
'struct bitmask' (variable-size) in order to still compile on RHEL 5,
with its numactl-devel-0.9.8.

* src/qemu/qemu_process.c [HAVE_NUMA]: Prefer back-compat mode.
(qemuProcessInitNumaMemoryPolicy): Use older nodemask_t.
2011-06-24 08:24:10 -06:00
Minoru Usui
b46832971c Add Memory Device Information to virSysinfoRead() from dmidecode type 17
* src/util/sysinfo.[ch]: also parse and save all the SMBIOS informations
  about memory modules
2011-06-24 22:22:09 +08:00
Minoru Usui
49156a7a11 Add Processor Information to virSysinfoRead() from dmidecode type 4
* src/util/sysinfo.c: add parsing and formatting of processor
  information data
2011-06-24 22:22:09 +08:00
Minoru Usui
532ce9c22f Cleanup virSysinfoRead()
* src/util/sysinfo.c: Separate BIOSInfo and SystemInfo part from
                      virSysinfoRead()
2011-06-24 22:22:09 +08:00
Daniel P. Berrange
789ab2cc9f Make sure virnetprotocol.[ch] are in BUILT_SOURCES
To ensure virnetprotocol.[ch] are generated before any other
files, add them to BUILT_SOURCES and MAINTAINERCLEANFILES.
At the same time, move ESX_DRIVER_GENERATED out of DISTCLEAN
and into MAINTAINERCLEANFILES, since they are included in
EXTRA_DIST

* src/Makefile.am: Add virnetprotocol.[ch] to BUILT_SOURCES
2011-06-24 15:19:41 +01:00
Eric Blake
acb31cf59b maint: typo fixes
* src/xenxs/xen_sxpr.c (xenParseSxprPCI): Comment fix.
* tests/object-locking.ml (driverTables): Likewise.
* tests/testutils.c (virtTestDifferenceBin): Likewise.
2011-06-24 08:01:10 -06:00
Daniel P. Berrange
d6bf7703d0 Fix some bugs in RPC protocol make rules
The Makefile.am rules for generating RPC protocol had a couple
of bugs

 - A instance of remote/rpcgen_fix.pl  was not changed
   to rpc/genprotocol.pl
 - A dep from rpc/virnetmessage.h on the generated
   rpc/virnetprotocol.h was missing
 - The generated rpc/virnetprotocol.[ch] were not listed
   in MAINTAINERCLEANFILES

* Makefile.am: Fix RPC protocol generation
2011-06-24 14:37:25 +01:00
Daniel P. Berrange
c0cd292933 Add missing translation of error message from QEMU reboot patch
* src/qemu/qemu_process.c: Add missing _(...)
2011-06-24 12:25:00 +01:00
Daniel P. Berrange
7479831311 Fix job type set in qemuMigrationPrepareDirect/PrepareTunnel
The qemuMigrationPrepareDirect/PrepareTunnel methods accidentally
set the domain job to  QEMU_JOB_MIGRATION_OUT when it should have
been  QEMU_JOB_MIGRATION_IN. This didn't have any ill-effect, but
it is none-the-less wrong.

* src/qemu/qemu_migration.c: Fix job type
2011-06-24 12:15:10 +01:00
Daniel P. Berrange
bd180de57b Avoid high privileges taint warning for QEMU session driver
The code emitting taint warnings was mistakenly thinking
that guests run from the QEMU session driver were tainted
for having high privileges. This is of course nonsense
since the session driver is always unprivileged

* src/qemu/qemu_domain.c: Don't warn for high privileges in
  non-privileged QEMU
2011-06-24 12:15:10 +01:00
Daniel P. Berrange
3ba937da42 Allow automatic kill of guests when a connection is closed
If an application is using libvirt + KVM as a piece of its
internal infrastructure to perform a specific task, it can
be desirable to guarentee the VM dies when the virConnectPtr
disconnects from libvirtd. This ensures the app can't leak
any VMs it was using. Adding VIR_DOMAIN_START_AUTOKILL as
a flag when starting guests enables this to be done.

* include/libvirt/libvirt.h.in: All VIR_DOMAIN_START_AUTOKILL
* src/qemu/qemu_driver.c: Support automatic killing of guests
  upon connection close
* tools/virsh.c: Add --autokill flag to 'start' and 'create'
  commands
2011-06-24 12:15:10 +01:00
Daniel P. Berrange
2c2effa1d7 Automatically kill target QEMU if migration aborts abnormally
Migration is a multi-step process

  1. Begin(src)
  2. Prepare(dst)
  3. Perform(src)
  4. Finish(dst)
  5. Confirm(src)

At step 2, a QEMU process is lauched in the destination to
accept the incoming migration. Occasionally the process
that is controlling the migration workflow aborts, and fails
to call step 4, Finish. This leaves a QEMU process running
on the target (albeit with paused CPUs). Unfortunately because
step 2 actives a job on the QEMU process, it is unkillable by
normal means.

By registering the VM for autokill against the src virConnectPtr
in step 2, we can ensure that the guest is forcefully killed off
if the connection is closed without step 4 being invoked

* src/qemu/qemu_migration.c: Register autokill in PrepareDirect
  and PrepareTunnel. Unregister autokill on successful run
  of Finish
* src/qemu/qemu_process.c: Unregister autokill when stopping a
  process
2011-06-24 12:15:10 +01:00
Daniel P. Berrange
558b7fd03d Add infrastructure to automatically destroy guests when a connection closes
Sometimes it is useful to be able to automatically destroy a guest when
a connection is closed. For example, kill an incoming migration if
the client managing the migration dies. This introduces a map between
guest 'uuid' strings and virConnectPtr objects. When a connection is
closed, any associated guests are killed off.

* src/qemu/qemu_conf.h: Add autokill hash table to qemu driver
* src/qemu/qemu_process.c, src/qemu/qemu_process.h: Add APIs
  for performing autokill of guests associated with a connection
* src/qemu/qemu_driver.c: Initialize autodestroy map
2011-06-24 12:15:10 +01:00
Daniel P. Berrange
42f43592be Support reboots with the QEMU driver
For controlled shutdown we issue a 'system_powerdown' command
to the QEMU monitor. This triggers an ACPI event which (most)
guest OS wire up to a controlled shutdown. There is no equiv
ACPI event to trigger a controlled reboot. This patch attempts
to fake a reboot.

 - In qemuDomainObjPrivatePtr we have a bool fakeReboot
   flag.
 - The virDomainReboot method sets this flag and then
   triggers a normal 'system_powerdown'.
 - The QEMU process is started with '-no-shutdown'
   so that the guest CPUs pause when it powers off the
   guest
 - When we receive the 'POWEROFF' event from QEMU JSON
   monitor if fakeReboot is not set we invoke the
   qemuProcessKill command and shutdown continues
   normally
 - If fakeReboot was set, we spawn a background thread
   which issues 'system_reset' to perform a warm reboot
   of the guest hardware. Then it issues 'cont' to
   start the CPUs again

* src/qemu/qemu_command.c: Add -no-shutdown flag if
  we have JSON support
* src/qemu/qemu_domain.h: Add 'fakeReboot' flag to
  qemuDomainObjPrivate struct
* src/qemu/qemu_driver.c: Fake reboot using the
  system_powerdown command if JSON support is available
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
  src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h,
  src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h: Add
  binding for system_reset command
* src/qemu/qemu_process.c: Reset the guest & start CPUs if
  fakeReboot is set
2011-06-24 12:13:47 +01:00
Daniel P. Berrange
b17b4afafd Move the RPC generator scripts into src/rpc
Move the daemon/remote_generator.pl to src/rpc/gendispatch.pl
and move the src/remote/rpcgen_fix.pl to src/rpc/genprotocol.pl

* daemon/Makefile.am: Update for new name/location of generator
* src/Makefile.am: Update for new name/location of generator
2011-06-24 11:48:49 +01:00
Daniel P. Berrange
434de30da5 Introduce generic RPC client objects
To facilitate creation of new clients using XDR RPC services,
pull alot of the remote driver code into a set of reusable
objects.

 - virNetClient: Encapsulates a socket connection to a
   remote RPC server. Handles all the network I/O for
   reading/writing RPC messages. Delegates RPC encoding
   and decoding to the registered programs

 - virNetClientProgram: Handles processing and dispatch
   of RPC messages for a single RPC (program,version).
   A program can register to receive async events
   from a client

 - virNetClientStream: Handles generic I/O stream
   integration to RPC layer

Each new client program now merely needs to define the list of
RPC procedures & events it wants and their handlers. It does
not need to deal with any of the network I/O functionality at
all.
2011-06-24 11:48:45 +01:00
Daniel P. Berrange
e23ec81db6 Introduce generic RPC module for advertising via MDNS
Allow RPC servers to advertise themselves using MDNS,
via Avahi

* src/rpc/virnetserver.c, src/rpc/virnetserver.h: Allow
  registration of MDNS services via avahi
* src/rpc/virnetserverservice.c, src/rpc/virnetserverservice.h: Add
  API to fetch the listen port number
* src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Add API to
  fetch the local port number
* src/rpc/virnetservermdns.c, src/rpc/virnetservermdns.h: Represent
  an MDNS advertisement
2011-06-24 11:48:41 +01:00
Daniel P. Berrange
4e00b1da8a Introduce generic RPC server objects
To facilitate creation of new daemons providing XDR RPC services,
pull a lot of the libvirtd daemon code into a set of reusable
objects.

 * virNetServer: A server contains one or more services which
   accept incoming clients. It maintains the list of active
   clients. It has a list of RPC programs which can be used
   by clients. When clients produce a complete RPC message,
   the server passes this onto the corresponding program for
   handling, and queues any response back with the client.

 * virNetServerClient: Encapsulates a single client connection.
   All I/O for the client is handled, reading & writing RPC
   messages.

 * virNetServerProgram: Handles processing and dispatch of
   RPC method calls for a single RPC (program,version).
   Multiple programs can be registered with the server.

 * virNetServerService: Encapsulates socket(s) listening for
   new connections. Each service listens on a single host/port,
   but may have multiple sockets if on a dual IPv4/6 host.

Each new daemon now merely has to define the list of RPC procedures
& their handlers. It does not need to deal with any network related
functionality at all.
2011-06-24 11:48:37 +01:00
Daniel P. Berrange
f5fa167e8d Integrate TLS/SASL directly into the socket APIs
This extends the basic virNetSocket APIs to allow them to have
a handle to the TLS/SASL session objects, once established.
This ensures that any data reads/writes are automagically
passed through the TLS/SASL encryption layers if required.

* src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Wire up
  SASL/TLS encryption
2011-06-24 11:48:30 +01:00
Daniel P. Berrange
bb1c9296f5 Generic module for handling SASL authentication & encryption
This provides two modules for handling SASL

 * virNetSASLContext provides the process-wide state, currently
   just a whitelist of usernames on the server and a one time
   library init call

 * virNetTLSSession provides the per-connection state, ie the
   SASL session itself. This also include APIs for providing
   data encryption/decryption once the session is established

* src/Makefile.am: Add to libvirt-net-rpc.la
* src/rpc/virnetsaslcontext.c, src/rpc/virnetsaslcontext.h: Generic
  SASL handling code
2011-06-24 11:48:25 +01:00
Daniel P. Berrange
30fd0bbbfc Generic module for handling TLS encryption and x509 certs
This provides two modules for handling TLS

 * virNetTLSContext provides the process-wide state, in particular
   all the x509 credentials, DH params and x509 whitelists
 * virNetTLSSession provides the per-connection state, ie the
   TLS session itself.

The virNetTLSContext provides APIs for validating a TLS session's
x509 credentials. The virNetTLSSession includes APIs for performing
the initial TLS handshake and sending/recving encrypted data

* src/Makefile.am: Add to libvirt-net-rpc.la
* src/rpc/virnettlscontext.c, src/rpc/virnettlscontext.h: Generic
  TLS handling code
2011-06-24 11:48:22 +01:00
Daniel P. Berrange
58b5b14e5e Introduce a generic object for using network sockets
Introduces a simple wrapper around the raw POSIX sockets APIs
and name resolution APIs. Allows for easy creation of client
and server sockets with correct usage of name resolution APIs
for protocol agnostic socket setup.

It can listen for UNIX and TCP stream sockets.

It can connect to UNIX, TCP streams directly, or indirectly
to UNIX sockets via an SSH tunnel or external command

* src/Makefile.am: Add to libvirt-net-rpc.la
* src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Generic
  sockets APIs
* tests/Makefile.am: Add socket test
* tests/virnetsockettest.c: New test case
* tests/testutils.c: Avoid overriding LIBVIRT_DEBUG settings
* tests/ssh.c: Dumb helper program for SSH tunnelling tests
2011-06-24 11:48:18 +01:00
Daniel P. Berrange
ceacc1dd4f Provide a simple object for encoding/decoding RPC messages
This provides a new struct that contains a buffer for the RPC
message header+payload, as well as a decoded copy of the message
header. There is an API for applying a XDR encoding & decoding
of the message headers and payloads. There are also APIs for
maintaining a simple FIFO queue of message instances.

Expected usage scenarios are:

To send a message

   msg = virNetMessageNew()

   ...fill in msg->header fields..
   virNetMessageEncodeHeader(msg)
   ...loook at msg->header fields to determine payload filter
   virNetMessageEncodePayload(msg, xdrfilter, data)
   ...send msg->bufferLength worth of data from buffer

To receive a message

   msg = virNetMessageNew()
   ...read VIR_NET_MESSAGE_LEN_MAX of data into buffer
   virNetMessageDecodeLength(msg)
   ...read msg->bufferLength-msg->bufferOffset of data into buffer
   virNetMessageDecodeHeader(msg)
   ...look at msg->header fields to determine payload filter
   virNetMessageDecodePayload(msg, xdrfilter, data)
   ...run payload processor

* src/Makefile.am: Add to libvirt-net-rpc.la
* src/rpc/virnetmessage.c, src/rpc/virnetmessage.h: Internal
  message handling API.
* testutils.c, testutils.h: Helper for printing binary differences
* virnetmessagetest.c: Validate all XDR encoding/decoding
2011-06-24 11:48:14 +01:00
Daniel P. Berrange
980a132a24 Defines the basics of a generic RPC protocol in XDR
This patch defines the basics of a generic RPC protocol in XDR.
This is wire ABI compatible with the original remote_protocol.x.
It takes everything except for the RPC calls / events from that
protocol

 - The basic header virNetMessageHeader (aka remote_message_header)
 - The error object virNetMessageError  (aka remote_error)
 - Two dummy objects virNetMessageDomain & virNetMessageNetwork
   sadly needed to keep virNetMessageError ABI compatible with
   the old remote_error

The RPC protocol supports method calls, async events and
bidirectional data streams as before

* src/Makefile.am: Add rules for generating RPC code from
  protocol & define a new libvirt-net-rpc.la helper library
* src/rpc/virnetprotocol.x: New generic RPC protocol
2011-06-24 11:48:10 +01:00
Eric Blake
178bab1c53 build: avoid python 2.4 build failure
On RHEL 5, I got:

/usr/bin/python ./generator.py /usr/bin/python
  File "./generator.py", line 427
    "virStreamFree", # Needed in custom virStream __del__, but free shouldn't
                   ^
SyntaxError: invalid syntax

* python/generator.py (function_skip_python_impl): Use same syntax
as other skip lists.
2011-06-23 22:09:00 -06:00
Eric Blake
ab228c81f2 build: avoid compiler failure
GCC complained about a C99 for-loop declaration outside of C99 mode
when compiling on RHEL 5.

* src/qemu/qemu_driver.c (qemudDomainPinVcpuFlags): Avoid C99 for
loop, since gcc 4.1.2 hates it.
2011-06-23 21:57:58 -06:00
David S. Wang
93d6fd1d09 documenting the 802.1Qbh parameters of a 'direct' interface
This patch adds documentation about the 802.1Qbh related parameters
of the virtualport element for 'direct' interfaces.

Signed-off-by: David S. Wang <dwang2@cisco.com>
Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: Vasanthy Kolluri <vkolluri@cisco.com>
2011-06-23 11:05:24 -06:00
Eric Blake
290247c753 build: update to latest gnulib
Gnulib has been busy, with 397 commits; it's easier to update now
even without any known libvirt issue to be fixed, rather than
having to analyze an even larger changeset later on.

* .gnulib: Update to latest, for lots of changes.
* bootstrap: Synchronize to upstream.
2011-06-23 10:52:08 -06:00
Stefan Berger
f7ed693666 build: fix compilation on systems missing libnl and new includes
This patch fixes the compilation of netlink.c and interface.c on those
systems missing either libnl or that have an older linux/if_link.h
include file not supporting macvtap or VF_PORTS.

WITH_MACVTAP is '1' if newer include files were detected, '0' otherwise.

IFLA_PORT_MAX is defined in linux/if_link.h if yet more functionality is
supported.
2011-06-23 11:54:11 -04:00