1#!/usr/bin/env perl
2
3use strict;
4use warnings;
5
6our $home;
7
8BEGIN {
9  use FindBin;
10  FindBin::again();
11
12  $home = ($ENV{NETDISCO_HOME} || $ENV{HOME});
13
14  # try to find a localenv if one isn't already in place.
15  if (!exists $ENV{PERL_LOCAL_LIB_ROOT}) {
16      use File::Spec;
17      my $localenv = File::Spec->catfile($FindBin::RealBin, 'localenv');
18      exec($localenv, $0, @ARGV) if -f $localenv;
19      $localenv = File::Spec->catfile($home, 'perl5', 'bin', 'localenv');
20      exec($localenv, $0, @ARGV) if -f $localenv;
21
22      die "Sorry, can't find libs required for App::Netdisco.\n"
23        if !exists $ENV{PERLBREW_PERL};
24  }
25}
26
27BEGIN {
28  use Path::Class;
29
30  # stuff useful locations into @INC and $PATH
31  unshift @INC,
32    dir($FindBin::RealBin)->parent->subdir('lib')->stringify,
33    dir($FindBin::RealBin, 'lib')->stringify;
34
35  use Config;
36  $ENV{PATH} = $FindBin::RealBin . $Config{path_sep} . $ENV{PATH};
37}
38
39use App::Netdisco;
40use Dancer ':script';
41use Dancer::Plugin::DBIC 'schema';
42
43use Try::Tiny;
44
45=head1 NAME
46
47netdisco-db-deploy - Database deployment for Netdisco
48
49=head1 USAGE
50
51This script upgrades or initialises a Netdisco database schema.
52
53 ~/bin/netdisco-db-deploy [--redeploy-all]
54
55This script connects to the database and runs without user interaction. If
56there's no Nedisco schema, it is deployed. If there's an unversioned schema
57then versioning is added, and updates applied.  Otherwise only necessary
58updates are applied to an already versioned schema.
59
60Pre-existing requirements are that there's a working database connection and a
61user with rights to create tables in that database. These settings are defined
62in your environment YAML file (default C<~/environments/deployment.yml>).
63
64If you wish to force the redeployment of all database configuration, pass the
65C<--redeploy-all> argument on the command line. This will reset your database
66version so the database scripts will run again, but no data will be deleted
67other than what's done via the upgrade scripts.
68
69For more database info see the
70L<netdisco wiki|https://github.com/netdisco/netdisco/wiki/Database-Tips>.
71
72=head1 VERSIONS
73
74=over 4
75
76=item *
77
78Version 1 is a completely empty database schema with no tables
79
80=item *
81
82Version 2 is the "classic" Netdisco database schema as of Netdisco 1.1
83
84=item *
85
86Versions 5 to 16 add patches for Netdisco 1.2
87
88=item *
89
90Version 17 onwards deploys schema upgrades for Netdisco 2
91
92=back
93
94=cut
95
96my $schema = schema('netdisco');
97
98if (scalar @ARGV and $ARGV[0] and $ARGV[0] eq '--redeploy-all') {
99    $schema->storage->dbh_do(
100      sub {
101        my ($storage, $dbh, @args) = @_;
102        $dbh->do('DROP TABLE dbix_class_schema_versions');
103      },
104    );
105}
106
107# installs the dbix_class_schema_versions table with version "1"
108# which corresponds to an empty schema
109if (not $schema->get_db_version) {
110    $schema->install(1);
111    $schema->storage->disconnect;
112}
113
114# test for existing schema at public release version, set v=2 if so
115try {
116    $schema->storage->dbh_do(sub {
117      my ($storage, $dbh) = @_;
118      $dbh->selectrow_arrayref("SELECT * FROM device WHERE 0 = 1");
119    });
120
121    $schema->_set_db_version({version => 2})
122      if $schema->get_db_version == 1;
123    $schema->storage->disconnect;
124};
125
126# upgrade from whatever dbix_class_schema_versions says, to $VERSION
127# except that get_db_version will be 0 at first deploy
128my $db_version = ($schema->get_db_version || 1);
129my $target_version = $schema->schema_version;
130
131# one step at a time, in case user has applied local changes already
132for (my $i = $db_version; $i < $target_version; $i++) {
133    my $next = $i + 1;
134    try {
135        $schema->upgrade_single_step($i, $next);
136    }
137    catch {
138        warn "Error: $_"
139          if $_ !~ m/(does not exist|already exists)/;
140
141        # set row in dbix_class_schema_versions table
142        $schema->_set_db_version({version => $next})
143          if $schema->get_db_version < $next;
144    };
145}
146
147exit 0;
148