omniti-labs/omnipitr

Timezones

Closed this issue · 18 comments

mjbnz commented

Rudimentary investigation shows that the timezone stored in the meta files is not useful for cleanup for some zones:

$ date
Tue May  7 03:44:38 UTC 2019
$ grep Timezone server.foo.com-meta-2019-05-07.tar.gz
Timezone: NZST
$ TZ=NZST date
Tue May  7 03:44:43 NZST 2019

Which gives problems with cleanup:

omnipitr-backup-cleanup : ERROR : When processing meta file (server.foo.com-meta-2019-05-07.tar.gz): $VAR1 = {
omnipitr-backup-cleanup : ERROR :           'started-epoch' => '1557181801',
omnipitr-backup-cleanup : ERROR :           'timezone' => 'NZST',
omnipitr-backup-cleanup : ERROR :           'hostname' => 'server.foo.com',
omnipitr-backup-cleanup : ERROR :           'min-xlog' => '0000000100000000000000CC',
omnipitr-backup-cleanup : ERROR :           'file_name' => 'server.foo.com-meta-2019-05-07.tar.gz'
omnipitr-backup-cleanup : ERROR :         };
omnipitr-backup-cleanup : ERROR : , regenerated filename was incorrect: server.foo.com-meta-2019-05-06.tar.gz. Ignoring metafile.

Very dirty hack to work around this was to symlink the short names to NZ:

# ls -l /usr/share/zoneinfo/NZ*
-rw-r--r-- 1 root root 2460 Mar 27 20:34 /usr/share/zoneinfo/NZ
lrwxrwxrwx 1 root root    2 May  7 03:25 /usr/share/zoneinfo/NZDT -> NZ
lrwxrwxrwx 1 root root    2 May  7 03:25 /usr/share/zoneinfo/NZST -> NZ

Which allows usage of NZST and NZDT zones:

$ date
Tue May  7 03:50:51 UTC 2019
$ TZ=NZST date
Tue May  7 15:50:52 NZST 2019

I'm guessing that something a little more robust than perl's localtime and %Z will be required to correctly check timestamps?

Thanks for the report. Will look into it.

I tried, but I can't replicate the problem. Are you absolutely sure, that you have NZST zoneinfo file on the server that runs omnipitr-backup-cleanup ?

Can you, please, on the server that runs omnipitr-backup-cleanup, download this script, and run it like this:

TZ=NZ ./test.pl
TZ=NZST ./test.pl
TZ=UTC ./test.pl

and provide me with outputs?

mjbnz commented

Certainly:

With NZST/NZDT links in place in /usr/share/zoneinfo as a workaround to make things work, results from the test script are as expected:

root@server:/usr/share/zoneinfo# ls -l NZ{,ST,DT}
-rw-r--r-- 1 root root 2460 Mar 27 20:34 NZ
lrwxrwxrwx 1 root root    2 May  7 03:25 NZDT -> NZ
lrwxrwxrwx 1 root root    2 May  7 03:25 NZST -> NZ
root@server:/usr/share/zoneinfo# TZ=NZ ~/test.pl
Before: 1557181801 , 1 , 30 , 10 , 7 , 4 , 119 , 2 , 126 , 0 , 2019-05-07 10:30:01 +1200 NZST
After:  1557181801 , 1 , 30 , 10 , 7 , 4 , 119 , 2 , 126 , 0 , 2019-05-07 10:30:01 +1200 NZST
[server.foo.com-meta-2019-05-07.tar.gz] vs. [server.foo.com-meta-2019-05-07.tar.gz]
root@server:/usr/share/zoneinfo# TZ=NZST ~/test.pl
Before: 1557181801 , 1 , 30 , 10 , 7 , 4 , 119 , 2 , 126 , 0 , 2019-05-07 10:30:01 +1200 NZST
After:  1557181801 , 1 , 30 , 10 , 7 , 4 , 119 , 2 , 126 , 0 , 2019-05-07 10:30:01 +1200 NZST
[server.foo.com-meta-2019-05-07.tar.gz] vs. [server.foo.com-meta-2019-05-07.tar.gz]
root@server:/usr/share/zoneinfo# TZ=UTC ~/test.pl
Before: 1557181801 , 1 , 30 , 22 , 6 , 4 , 119 , 1 , 125 , 0 , 2019-05-06 22:30:01 +0000 UTC
After:  1557181801 , 1 , 30 , 10 , 7 , 4 , 119 , 2 , 126 , 0 , 2019-05-07 10:30:01 +1200 NZST
[server.foo.com-meta-2019-05-07.tar.gz] vs. [server.foo.com-meta-2019-05-07.tar.gz]

Remove those links that I added as a workaround (so, back to the environment that I discovered this bug):

root@server:/usr/share/zoneinfo# rm NZ{ST,DT}

Results are broken (all After results do not correctly list NZST from the metadata as +1200):

root@server:/usr/share/zoneinfo# TZ=NZ ~/test.pl
Before: 1557181801 , 1 , 30 , 10 , 7 , 4 , 119 , 2 , 126 , 0 , 2019-05-07 10:30:01 +1200 NZST
After:  1557181801 , 1 , 30 , 22 , 6 , 4 , 119 , 1 , 125 , 0 , 2019-05-06 22:30:01 +0000 NZST
[server.foo.com-meta-2019-05-07.tar.gz] vs. [server.foo.com-meta-2019-05-06.tar.gz]
root@server:/usr/share/zoneinfo# TZ=NZST ~/test.pl
Before: 1557181801 , 1 , 30 , 22 , 6 , 4 , 119 , 1 , 125 , 0 , 2019-05-06 22:30:01 +0000 NZST
After:  1557181801 , 1 , 30 , 22 , 6 , 4 , 119 , 1 , 125 , 0 , 2019-05-06 22:30:01 +0000 NZST
[server.foo.com-meta-2019-05-07.tar.gz] vs. [server.foo.com-meta-2019-05-06.tar.gz]
root@server:/usr/share/zoneinfo# TZ=UTC ~/test.pl
Before: 1557181801 , 1 , 30 , 22 , 6 , 4 , 119 , 1 , 125 , 0 , 2019-05-06 22:30:01 +0000 UTC
After:  1557181801 , 1 , 30 , 22 , 6 , 4 , 119 , 1 , 125 , 0 , 2019-05-06 22:30:01 +0000 NZST
[server.foo.com-meta-2019-05-07.tar.gz] vs. [server.foo.com-meta-2019-05-06.tar.gz]
mjbnz commented

... I'll add, I'm not sure what the right answer is, but a start might be to store Olsen time zones in the meta file?

Edit: We use Pacific/Auckland here, not NZST or NZDT. The abbreviations are outputs of time calculations to show when DST is active, but that's about it. For example:

root@server:/usr/share/zoneinfo# TZ=Pacific/Auckland date
Wed May 15 11:16:41 NZST 2019
root@server:/usr/share/zoneinfo# TZ=Pacific/Auckland date --date="3 months ago"
Fri Feb 15 12:16:50 NZDT 2019

Edit2: using the NZ abbreviation also works, but it's deprecated.

Edit3: and just as another example:

root@server:/usr/share/zoneinfo# date
Tue May 14 23:19:33 UTC 2019
root@server:/usr/share/zoneinfo# TZ=CST date
Tue May 14 23:19:38 CST 2019
root@server:/usr/share/zoneinfo# TZ=CDT date
Tue May 14 23:19:41 CDT 2019
root@server:/usr/share/zoneinfo# TZ=America/Chicago date
Tue May 14 18:19:58 CDT 2019
root@server:/usr/share/zoneinfo# TZ=America/Chicago date --date="3 months ago"
Thu Feb 14 17:20:14 CST 2019

OK. Can I ask you to:

  • provide me with information about os (distro, version)
  • perl version and details (perl -V output)
  • do: export TZ=NZST; strace -ff -o for.depesz.log -s 256 -tt -T perl test.pl
  • the strace command will generate couple (maybe just one) file. compress them and attach to this issue.
    this will generate
mjbnz commented

with or without the links in place in /usr/share/zoneinfo ?

with. Without it will definitely not work, but with links in place, it should work, so let's see why it doesn't.

mjbnz commented

I'm very confused - with the links in place, it does work. Note that the test situation I'm showing you is where the backup was made on a host with the Pacific/Auckland (currently NZST) timezone, and cleanup was running on a host set to Etc/UTC. The timestamp is 07/05/19 in NZST (same as the meta filename), and 06/05/19 in UTC (which is what perl is calculating without the links in place - like it's the same as the local system time - UTC).

I can't really tell what's happening, but it looks that for whatever reason perl wasn't able to read the tz description on the backup host, when it was trying to do the cleanup.

Not sure what could be solution in here, other than using UTC everywhere.

mjbnz commented

I'm not sure I can be more clear about what's happening. Perl is doing exactly the same as /bin/date in my testing above. It's trying to use the output of strftime('%Z', localtime); which is saved to the meta file, as a timezone to regenerate the date that the backup was made, to verify the meta filename.

The short form timezone output from %Z is NOT a valid value to use for $ENV{TZ}.

OK, then this leads to question: how do I get proper value for TZ?

Just check ENV["TZ"]? What if it's not set?

There is POSIX::tzname, but it returns two names - one for standard, and one for daylight savings time.

Currently, the only sane solution I can see is to use gmtime() for filename generation, but it will have the side effect that names will not match what you see by calling "date".

Any opinion on what you'd like to happen?

Hi, so I,ve read some on the Olson module, and generated this test script: https://gist.github.com/depesz/c7e11c0e8d731533ef25b5f6f851e474

Can you please run it in your environment, and let me know if it works OK?

it's been a month, i assume the problem is no longer important/valid.

mjbnz commented

No, it's still important, I just haven't gotten around to testing your script - The system doesn't have Time::Zone::Olson available as a package, and I hadn't had time to install from cpan.

mjbnz commented

Instead of using Date::Time::Olson, I tweaked your script to just use DateTime which uses Olson timezones as well. Here's the script:

#!/usr/bin/env perl

use strict;
use POSIX qw( strftime );
use DateTime;

sub strftime_at_timezone_olson {
    my ( $format, $time, $timezone ) = @_;

    my $dt    = DateTime->from_epoch( epoch => $time );

    $dt->set_time_zone( $timezone );

    return $dt->strftime( $format );
}

my $meta = {
    'started-epoch' => '1557181801',
    'timezone'      => 'NZST',
    'hostname'      => 'server.foo.com',
    'min-xlog'      => '0000000100000000000000CC',
    'file_name'     => 'server.foo.com-meta-2019-05-07.tar.gz'
};
my $filename_mask = 'server.foo.com-meta-%Y-%m-%d.tar.gz';

my $meta_filename_verification = strftime_at_timezone_olson( $filename_mask, $meta->{ 'started-epoch' }, $meta->{ 'timezone' } );

printf "[%s] vs. [%s]\n", $meta->{ 'file_name' }, $meta_filename_verification;

exit;

And the Output:
$meta->timezone set to NZST:

root@server:~# ./olson.pl
Invalid offset: NZST

$meta->timezone set to Pacific/Auckland:

root@server:~# ./olson.pl
[server.foo.com-meta-2019-05-07.tar.gz] vs. [server.foo.com-meta-2019-05-07.tar.gz]

$meta->timezone set to Etc/UTC:

root@server:~# ./olson.pl
[server.foo.com-meta-2019-05-07.tar.gz] vs. [server.foo.com-meta-2019-05-06.tar.gz]

Well, given that DateTime can't parse NZST it is of no big use.

I just committed b5e3352 that solves the problem another way.

It makes all future meta files contain time zone as offset, and as such it will be parseable, and usable by normal POSIX::tzset().

I tested it myself, and it looks that after this change cleanup works correctly.

Of course - you will need to manually change meta files that were generated previously, but that shouldn't be big work.

Please check if it solves your case, and let me know, so I can release new version.

mjbnz commented

Well, given that DateTime can't parse NZST it is of no big use.

That's the point. NZST is not a valid timezone. The correct thing to do is to store the Olson timezone in the meta files, not the output of strftime('%Z', localtime);, which doesn't provide a valid timezone. Storing offset is the next best thing, so I'll test your code in the next week or so and let you know.