cloud-mu 3.6.9 → 3.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. checksums.yaml +4 -4
  2. data/Berksfile +2 -3
  3. data/Berksfile.lock +11 -14
  4. data/bin/mu-aws-setup +16 -4
  5. data/bin/mu-configure +2 -1
  6. data/cloud-mu.gemspec +2 -2
  7. data/cookbooks/mu-firewall/Berksfile +1 -1
  8. data/cookbooks/mu-firewall/attributes/default.rb +2 -2
  9. data/cookbooks/mu-firewall/metadata.rb +3 -3
  10. data/cookbooks/mu-firewall/recipes/default.rb +11 -2
  11. data/cookbooks/mu-master/Berksfile +1 -1
  12. data/cookbooks/mu-master/attributes/default.rb +14 -1
  13. data/cookbooks/mu-master/files/default/389ds-perl/ASDialogs.pm +173 -0
  14. data/cookbooks/mu-master/files/default/389ds-perl/AdminMigration.pm +569 -0
  15. data/cookbooks/mu-master/files/default/389ds-perl/AdminServer.pm +952 -0
  16. data/cookbooks/mu-master/files/default/389ds-perl/AdminUtil.pm +983 -0
  17. data/cookbooks/mu-master/files/default/389ds-perl/ConfigDSDialogs.pm +449 -0
  18. data/cookbooks/mu-master/files/default/389ds-perl/DSCreate.pm +1551 -0
  19. data/cookbooks/mu-master/files/default/389ds-perl/DSDialogs.pm +233 -0
  20. data/cookbooks/mu-master/files/default/389ds-perl/DSMigration.pm +1175 -0
  21. data/cookbooks/mu-master/files/default/389ds-perl/DSUpdate.pm +534 -0
  22. data/cookbooks/mu-master/files/default/389ds-perl/DSUpdateDialogs.pm +152 -0
  23. data/cookbooks/mu-master/files/default/389ds-perl/DSUtil.pm +1710 -0
  24. data/cookbooks/mu-master/files/default/389ds-perl/Dialog.pm +249 -0
  25. data/cookbooks/mu-master/files/default/389ds-perl/DialogManager.pm +212 -0
  26. data/cookbooks/mu-master/files/default/389ds-perl/FileConn.pm +461 -0
  27. data/cookbooks/mu-master/files/default/389ds-perl/Inf.pm +268 -0
  28. data/cookbooks/mu-master/files/default/389ds-perl/Migration.pm +327 -0
  29. data/cookbooks/mu-master/files/default/389ds-perl/RegDSDialogs.pm +94 -0
  30. data/cookbooks/mu-master/files/default/389ds-perl/Resource.pm +137 -0
  31. data/cookbooks/mu-master/files/default/389ds-perl/Setup.pm +240 -0
  32. data/cookbooks/mu-master/files/default/389ds-perl/SetupDialogs.pm +243 -0
  33. data/cookbooks/mu-master/files/default/389ds-perl/SetupLog.pm +82 -0
  34. data/cookbooks/mu-master/files/default/setCertName.ldif +4 -0
  35. data/cookbooks/mu-master/libraries/mu.rb +2 -2
  36. data/cookbooks/mu-master/metadata.rb +1 -1
  37. data/cookbooks/mu-master/recipes/389ds.rb +71 -32
  38. data/cookbooks/mu-master/recipes/basepackages.rb +5 -0
  39. data/cookbooks/mu-master/recipes/default.rb +16 -5
  40. data/cookbooks/mu-master/recipes/init.rb +59 -4
  41. data/cookbooks/mu-master/recipes/ssl-certs.rb +6 -0
  42. data/cookbooks/mu-master/recipes/sssd.rb +85 -62
  43. data/cookbooks/mu-master/recipes/update_nagios_only.rb +7 -1
  44. data/cookbooks/mu-master/templates/default/389-directory-setup.inf.erb +11 -26
  45. data/cookbooks/mu-master/templates/default/sssd.conf.erb +18 -8
  46. data/cookbooks/mu-tools/files/default/Mu_CA.pem +33 -0
  47. data/cookbooks/mu-tools/metadata.rb +0 -1
  48. data/cookbooks/mu-tools/recipes/set_local_fw.rb +7 -1
  49. data/cookbooks/mu-tools/templates/amazon/sshd_config.erb +5 -1
  50. data/cookbooks/nagios/CHANGELOG.md +679 -0
  51. data/cookbooks/nagios/LICENSE +201 -0
  52. data/cookbooks/nagios/README.md +340 -0
  53. data/cookbooks/nagios/attributes/config.rb +163 -0
  54. data/cookbooks/nagios/attributes/default.rb +204 -0
  55. data/cookbooks/nagios/libraries/base.rb +311 -0
  56. data/cookbooks/nagios/libraries/command.rb +68 -0
  57. data/cookbooks/nagios/libraries/contact.rb +229 -0
  58. data/cookbooks/nagios/libraries/contactgroup.rb +111 -0
  59. data/cookbooks/{firewall/recipes/disable_firewall.rb → nagios/libraries/custom_option.rb} +20 -7
  60. data/cookbooks/nagios/libraries/data_bag_helper.rb +23 -0
  61. data/cookbooks/nagios/libraries/default.rb +90 -0
  62. data/cookbooks/nagios/libraries/helpers.rb +229 -0
  63. data/cookbooks/nagios/libraries/host.rb +410 -0
  64. data/cookbooks/nagios/libraries/hostdependency.rb +178 -0
  65. data/cookbooks/nagios/libraries/hostescalation.rb +170 -0
  66. data/cookbooks/nagios/libraries/hostgroup.rb +117 -0
  67. data/cookbooks/nagios/libraries/nagios.rb +277 -0
  68. data/cookbooks/nagios/libraries/resource.rb +59 -0
  69. data/cookbooks/nagios/libraries/service.rb +449 -0
  70. data/cookbooks/nagios/libraries/servicedependency.rb +213 -0
  71. data/cookbooks/nagios/libraries/serviceescalation.rb +193 -0
  72. data/cookbooks/nagios/libraries/servicegroup.rb +142 -0
  73. data/cookbooks/nagios/libraries/timeperiod.rb +159 -0
  74. data/cookbooks/nagios/libraries/users_helper.rb +54 -0
  75. data/cookbooks/nagios/metadata.json +44 -0
  76. data/cookbooks/nagios/metadata.rb +22 -0
  77. data/cookbooks/nagios/recipes/_load_databag_config.rb +153 -0
  78. data/cookbooks/nagios/recipes/_load_default_config.rb +241 -0
  79. data/cookbooks/nagios/recipes/apache.rb +114 -0
  80. data/cookbooks/nagios/recipes/default.rb +41 -0
  81. data/cookbooks/nagios/recipes/nginx.rb +114 -0
  82. data/cookbooks/nagios/recipes/pagerduty.rb +95 -0
  83. data/cookbooks/nagios/recipes/server.rb +182 -0
  84. data/cookbooks/nagios/recipes/server_package.rb +85 -0
  85. data/cookbooks/nagios/recipes/server_source.rb +137 -0
  86. data/cookbooks/nagios/resources/command.rb +34 -0
  87. data/cookbooks/nagios/resources/conf.rb +52 -0
  88. data/cookbooks/nagios/resources/contact.rb +34 -0
  89. data/cookbooks/nagios/resources/contactgroup.rb +35 -0
  90. data/cookbooks/nagios/resources/host.rb +35 -0
  91. data/cookbooks/nagios/resources/hostdependency.rb +35 -0
  92. data/cookbooks/nagios/resources/hostescalation.rb +36 -0
  93. data/cookbooks/nagios/resources/hostgroup.rb +35 -0
  94. data/cookbooks/nagios/resources/resource.rb +34 -0
  95. data/cookbooks/nagios/resources/service.rb +35 -0
  96. data/cookbooks/nagios/resources/servicedependency.rb +35 -0
  97. data/cookbooks/nagios/resources/serviceescalation.rb +35 -0
  98. data/cookbooks/nagios/resources/servicegroup.rb +35 -0
  99. data/cookbooks/nagios/resources/timeperiod.rb +35 -0
  100. data/cookbooks/nagios/templates/apache2.conf.erb +102 -0
  101. data/cookbooks/nagios/templates/cgi.cfg.erb +266 -0
  102. data/cookbooks/nagios/templates/commands.cfg.erb +13 -0
  103. data/cookbooks/nagios/templates/contacts.cfg.erb +37 -0
  104. data/cookbooks/nagios/templates/hostgroups.cfg.erb +25 -0
  105. data/cookbooks/nagios/templates/hosts.cfg.erb +15 -0
  106. data/cookbooks/nagios/templates/htpasswd.users.erb +6 -0
  107. data/cookbooks/nagios/templates/nagios.cfg.erb +22 -0
  108. data/cookbooks/nagios/templates/nginx.conf.erb +80 -0
  109. data/cookbooks/nagios/templates/pagerduty.cgi.erb +185 -0
  110. data/cookbooks/nagios/templates/resource.cfg.erb +27 -0
  111. data/cookbooks/nagios/templates/servicedependencies.cfg.erb +15 -0
  112. data/cookbooks/nagios/templates/servicegroups.cfg.erb +14 -0
  113. data/cookbooks/nagios/templates/services.cfg.erb +14 -0
  114. data/cookbooks/nagios/templates/spawn-fcgi.erb +10 -0
  115. data/cookbooks/nagios/templates/templates.cfg.erb +31 -0
  116. data/cookbooks/nagios/templates/timeperiods.cfg.erb +13 -0
  117. data/extras/platform_berksfile_base +3 -3
  118. data/extras/python_rpm/build.sh +4 -4
  119. data/extras/python_rpm/muthon.spec +2 -4
  120. data/extras/vault_tools/export_vaults.sh +11 -1
  121. data/install/installer +1 -1
  122. data/modules/mu/kittens.rb +27523 -0
  123. data/modules/mu/master/ldap.rb +48 -31
  124. data/modules/mu/master.rb +69 -0
  125. data/modules/mu/mu.yaml.rb +351 -0
  126. data/modules/mu/providers/aws/firewall_rule.rb +3 -1
  127. data/modules/mu/providers/aws.rb +27 -19
  128. data/modules/mu/providers/google.rb +1 -1
  129. data/modules/mu.rb +5 -4
  130. metadata +99 -48
  131. data/cookbooks/firewall/CHANGELOG.md +0 -488
  132. data/cookbooks/firewall/LICENSE +0 -202
  133. data/cookbooks/firewall/README.md +0 -366
  134. data/cookbooks/firewall/TODO.md +0 -6
  135. data/cookbooks/firewall/attributes/default.rb +0 -5
  136. data/cookbooks/firewall/attributes/firewalld.rb +0 -8
  137. data/cookbooks/firewall/attributes/iptables.rb +0 -17
  138. data/cookbooks/firewall/attributes/ufw.rb +0 -12
  139. data/cookbooks/firewall/attributes/windows.rb +0 -8
  140. data/cookbooks/firewall/libraries/helpers.rb +0 -105
  141. data/cookbooks/firewall/libraries/helpers_firewalld.rb +0 -116
  142. data/cookbooks/firewall/libraries/helpers_firewalld_dbus.rb +0 -72
  143. data/cookbooks/firewall/libraries/helpers_iptables.rb +0 -112
  144. data/cookbooks/firewall/libraries/helpers_nftables.rb +0 -170
  145. data/cookbooks/firewall/libraries/helpers_ufw.rb +0 -142
  146. data/cookbooks/firewall/libraries/helpers_windows.rb +0 -129
  147. data/cookbooks/firewall/libraries/provider_firewall_firewalld.rb +0 -179
  148. data/cookbooks/firewall/libraries/provider_firewall_iptables.rb +0 -171
  149. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb +0 -200
  150. data/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb +0 -200
  151. data/cookbooks/firewall/libraries/provider_firewall_rule.rb +0 -34
  152. data/cookbooks/firewall/libraries/provider_firewall_ufw.rb +0 -138
  153. data/cookbooks/firewall/libraries/provider_firewall_windows.rb +0 -126
  154. data/cookbooks/firewall/libraries/resource_firewall.rb +0 -26
  155. data/cookbooks/firewall/libraries/resource_firewall_rule.rb +0 -52
  156. data/cookbooks/firewall/metadata.json +0 -40
  157. data/cookbooks/firewall/metadata.rb +0 -15
  158. data/cookbooks/firewall/recipes/default.rb +0 -76
  159. data/cookbooks/firewall/recipes/firewalld.rb +0 -87
  160. data/cookbooks/firewall/resources/firewalld.rb +0 -28
  161. data/cookbooks/firewall/resources/firewalld_config.rb +0 -39
  162. data/cookbooks/firewall/resources/firewalld_helpers.rb +0 -106
  163. data/cookbooks/firewall/resources/firewalld_icmptype.rb +0 -88
  164. data/cookbooks/firewall/resources/firewalld_ipset.rb +0 -104
  165. data/cookbooks/firewall/resources/firewalld_policy.rb +0 -115
  166. data/cookbooks/firewall/resources/firewalld_service.rb +0 -98
  167. data/cookbooks/firewall/resources/firewalld_zone.rb +0 -118
  168. data/cookbooks/firewall/resources/nftables.rb +0 -71
  169. data/cookbooks/firewall/resources/nftables_rule.rb +0 -113
  170. data/cookbooks/firewall/templates/default/ufw/default.erb +0 -13
  171. /data/cookbooks/{firewall → nagios}/chefignore +0 -0
  172. /data/cookbooks/{firewall → nagios}/renovate.json +0 -0
@@ -0,0 +1,1175 @@
1
+ # BEGIN COPYRIGHT BLOCK
2
+ # Copyright (C) 2013 Red Hat, Inc.
3
+ # All rights reserved.
4
+ #
5
+ # License: GPL (version 3 or any later version).
6
+ # See LICENSE for details.
7
+ # END COPYRIGHT BLOCK
8
+ #
9
+
10
+ ###########################
11
+ #
12
+ # This perl module provides a way to set up a new installation after
13
+ # the binaries have already been extracted. This is typically after
14
+ # using native packaging support to install the package e.g. RPM,
15
+ # pkgadd, depot, etc. This script will show the license, readme,
16
+ # dsktune, then run the usual setup pre and post installers.
17
+ #
18
+ ##########################
19
+
20
+ package DSMigration;
21
+ use Migration;
22
+ use DSUtil;
23
+ use Inf;
24
+ use DSCreate;
25
+ use DSUpdate;
26
+
27
+ # tempfiles
28
+ use File::Temp qw(tempfile tempdir);
29
+ use File::Basename qw(basename);
30
+
31
+ # absolute path handling
32
+ use Cwd qw(realpath);
33
+
34
+ # load perldap
35
+ use Mozilla::LDAP::Conn;
36
+ use Mozilla::LDAP::Utils qw(normalizeDN);
37
+ use Mozilla::LDAP::API qw(ldap_explode_dn);
38
+ use Mozilla::LDAP::LDIF;
39
+
40
+ use Carp;
41
+
42
+ use Exporter;
43
+ @ISA = qw(Exporter);
44
+ @EXPORT = qw(migrateDS);
45
+ @EXPORT_OK = qw(migrateDS);
46
+
47
+ use strict;
48
+
49
+ use SetupLog;
50
+
51
+ # these are the attributes for which we will always use
52
+ # the new value, or which do not apply anymore
53
+ # for the next major release e.g. when we support migration from the
54
+ # current release 1.1.x to 1.2 or 2.0, the old version number will
55
+ # become quite important for migration - for example, when migrating
56
+ # from older than 1.1 to 1.1.x, we need to add the attributes in the
57
+ # table below to the new entry because the attribute didn't exist
58
+ # at all in the old server version - however, when migrating from
59
+ # e.g. 1.1.x to 2.0, we must preserve the old value - this means
60
+ # if the user has deleted the attribute from the entry, we must
61
+ # "migrate" that deletion by removing the attribute from the new
62
+ # entry
63
+ my %ignoreOld =
64
+ (
65
+ 'nsslapd-errorlog' => 'nsslapd-errorlog',
66
+ 'nsslapd-accesslog' => 'nsslapd-accesslog',
67
+ 'nsslapd-auditlog' => 'nsslapd-auditlog',
68
+ 'nskeyfile' => 'nsKeyfile',
69
+ 'nscertfile' => 'nsCertfile',
70
+ 'nsslapd-pluginpath' => 'nsslapd-pluginPath',
71
+ 'nsslapd-plugintype' => 'nsslapd-pluginType',
72
+ 'nsslapd-pluginversion' => 'nsslapd-pluginVersion',
73
+ 'nsslapd-plugin-depends-on-named' => 'nsslapd-plugin-depends-on-named',
74
+ # these are new attrs that we should just pass through
75
+ 'nsslapd-allow-unauthenticated-binds' => 'nsslapd-allow-unauthenticated-binds',
76
+ 'nsslapd-allow-anonymous-access' => 'nsslapd-allow-anonymous-access',
77
+ 'nsslapd-localssf' => 'nsslapd-localssf',
78
+ 'nsslapd-minssf' => 'nsslapd-minssf',
79
+ 'nsslapd-saslpath' => 'nsslapd-saslpath',
80
+ 'nsslapd-rundir' => 'nsslapd-rundir',
81
+ 'nsslapd-schemadir' => 'nsslapd-schemadir',
82
+ 'nsslapd-lockdir' => 'nsslapd-lockdir',
83
+ 'nsslapd-tmpdir' => 'nsslapd-tmpdir',
84
+ 'nsslapd-certdir' => 'nsslapd-certdir',
85
+ 'nsslapd-ldifdir' => 'nsslapd-ldifdir',
86
+ 'nsslapd-bakdir' => 'nsslapd-bakdir',
87
+ 'nsslapd-instancedir' => 'nsslapd-instancedir',
88
+ 'nsslapd-ldapifilepath' => 'nsslapd-ldapifilepath',
89
+ 'nsslapd-ldapilisten' => 'nsslapd-ldapilisten',
90
+ 'nsslapd-ldapiautobind' => 'nsslapd-ldapiautobind',
91
+ 'nsslapd-ldapimaprootdn' => 'nsslapd-ldapimaprootdn',
92
+ 'nsslapd-ldapimaptoentries' => 'nsslapd-ldapimaptoentries',
93
+ 'nsslapd-ldapiuidnumbertype' => 'nsslapd-ldapiuidnumbertype',
94
+ 'nsslapd-ldapigidnumbertype' => 'nsslapd-ldapigidnumbertype',
95
+ 'nsslapd-ldapientrysearchbase' => 'nsslapd-ldapientrysearchbase',
96
+ 'nsslapd-ldapiautodnsuffix' => 'nsslapd-ldapiautodnsuffix',
97
+ 'numsubordinates' => 'numSubordinates',
98
+ # for these, we just want to use the default values, even if they were
99
+ # set in 7.1 or later
100
+ 'nsslapd-db-private-import-mem' => 'nsslapd-db-private-import-mem',
101
+ 'nsslapd-import-cache-autosize' => 'nsslapd-import-cache-autosize',
102
+ # nsslapd-allidsthreshold does not exist anymore
103
+ # the analogous concept is nsslapd-idlistscanlimit for searches
104
+ 'nsslapd-allidsthreshold' => 'nsslapd-allidsthreshold'
105
+ );
106
+
107
+ # these are the obsolete entries we do not migrate
108
+ my %ignoreOldEntries =
109
+ (
110
+ 'cn=presence,cn=plugins,cn=config' => 'cn=presence,cn=plugins,cn=config',
111
+ 'cn=aim presence,cn=presence,cn=plugins,cn=config' => 'cn=aim presence,cn=presence,cn=plugins,cn=config',
112
+ 'cn=icq presence,cn=presence,cn=plugins,cn=config' => 'cn=icq presence,cn=presence,cn=plugins,cn=config',
113
+ 'cn=yahoo presence,cn=presence,cn=plugins,cn=config' => 'cn=yahoo presence,cn=presence,cn=plugins,cn=config'
114
+ );
115
+
116
+
117
+ # these are the attributes for which we will always use
118
+ # the old value
119
+ my %alwaysUseOld =
120
+ (
121
+ 'aci' => 'aci'
122
+ );
123
+
124
+ sub getDBVERSION {
125
+ my $olddbdir = shift;
126
+ my $data = shift;
127
+
128
+ open DBVERSION, "$olddbdir/DBVERSION" or
129
+ return ('error_reading_dbversion', $olddbdir, $!);
130
+ my $line = <DBVERSION>;
131
+ close DBVERSION;
132
+ chomp($line);
133
+ @{$data} = split("/", $line);
134
+ return ();
135
+ }
136
+
137
+ sub isOldDatabase {
138
+ my $olddbdir = shift;
139
+ my $errs = shift; # array ref
140
+ # check old DBVERSION file
141
+ my @verinfo;
142
+ if (@{$errs} = getDBVERSION($olddbdir, \@verinfo)) {
143
+ return 0;
144
+ }
145
+
146
+ if ((($verinfo[0] =~ /^netscape/i) or ($verinfo[0] =~ /^iplanet/i)) and
147
+ (($verinfo[1] =~ /^6/) or ($verinfo[1] =~ /^5/) or ($verinfo[1] =~ /^4/))) {
148
+ return 1;
149
+ }
150
+
151
+ return 0;
152
+ }
153
+
154
+ sub getNewDbDir {
155
+ my ($ent, $attr, $mig, $inst) = @_;
156
+ my $newval;
157
+ my %objclasses = map { lc($_) => $_ } $ent->getValues('objectclass');
158
+ my $cn = $ent->getValues('cn');
159
+ # there is one case where we want to just use the existing db directory
160
+ # that's the case where the user has moved the indexes and/or the
161
+ # transaction logs to different partitions for performance
162
+ # in that case, the old directory will not be the same as the default,
163
+ # and the directory will exist
164
+ # for cross platform, we should just use the new default location
165
+ if (!$mig->{crossplatform}) {
166
+ my $oldval = $ent->getValues($attr);
167
+ my $absoldval = realpath($oldval) || $oldval;
168
+ my $olddefault = "$mig->{actualsroot}/$inst";
169
+ if (-d $absoldval and ($absoldval !~ /^$olddefault/)) {
170
+ debug(2, "Keeping old value [$absoldval] for attr $attr in entry ", $ent->getDN(), "\n");
171
+ return $oldval;
172
+ }
173
+ }
174
+ # otherwise, just use the new default locations
175
+ if ("") {
176
+ if ($objclasses{nsbackendinstance}) {
177
+ $newval = "/var/$mig->{pkgname}/$inst/db/$cn";
178
+ } elsif (lc $cn eq 'config') {
179
+ $newval = "/var/$mig->{pkgname}/$inst/db";
180
+ } elsif (lc $cn eq 'changelog5') {
181
+ $newval = "/var/$mig->{pkgname}/$inst/changelogdb";
182
+ }
183
+ } else {
184
+ if ($objclasses{nsbackendinstance}) {
185
+ $newval = "/var/lib/$mig->{pkgname}/$inst/db/$cn";
186
+ } elsif (lc $cn eq 'config') {
187
+ $newval = "/var/lib/$mig->{pkgname}/$inst/db";
188
+ } elsif (lc $cn eq 'changelog5') {
189
+ $newval = "/var/lib/$mig->{pkgname}/$inst/changelogdb";
190
+ }
191
+ }
192
+ debug(2, "New value [$newval] for attr $attr in entry ", $ent->getDN(), "\n");
193
+ return $newval;
194
+ }
195
+
196
+ sub migrateCredentials {
197
+ my ($ent, $attr, $mig, $inst) = @_;
198
+ my $oldval = $ent->getValues($attr);
199
+ my $qoldval = shellEscape($oldval);
200
+
201
+ # Older versions of the server on x86 systems and other systems that do not use network byte order
202
+ # stored the credentials incorrectly. The first step is to determine if this is the case. We
203
+ # migrate using the same server root to see if we get the same output as we input.
204
+ debug(3, "In migrateCredentials - see how old credentials were encoded.\n");
205
+ my $testval = `/usr/bin/migratecred -o $mig->{actualsroot}/$inst -n $mig->{actualsroot}/$inst -c $qoldval`;
206
+ chomp($testval);
207
+ if ($testval ne $oldval) { # need to turn on the special flag
208
+ debug(3, "Credentials not encoded correctly. oldval $oldval not equal to testval $testval. The value will be re-encoded correctly.\n");
209
+ $ENV{MIGRATE_BROKEN_PWD} = "1"; # decode and re-encode correctly
210
+ }
211
+
212
+ debug(3, "Executing /usr/bin/migratecred -o $mig->{actualsroot}/$inst -n /etc/dirsrv/$inst -c $qoldval . . .\n");
213
+ my $newval = `/usr/bin/migratecred -o $mig->{actualsroot}/$inst -n /etc/dirsrv/$inst -c $qoldval`;
214
+ chomp($newval);
215
+ delete $ENV{MIGRATE_BROKEN_PWD}; # clear the flag, if set
216
+ debug(3, "Converted old value [$oldval] to new value [$newval] for attr $attr in entry ", $ent->getDN(), "\n");
217
+ return $newval;
218
+ }
219
+
220
+ sub removensState {
221
+ my ($ent, $attr, $mig, $inst) = @_;
222
+ my $newval;
223
+
224
+ # nsstate is binary and cannot be migrated cross platform
225
+ if (!$mig->{crossplatform}) {
226
+ $newval = $ent->getValues($attr);
227
+ }
228
+
229
+ return $newval;
230
+ }
231
+
232
+ sub migIdlSwitch {
233
+ my ($ent, $attr, $mig, $inst) = @_;
234
+ my $newval;
235
+
236
+ # if doing cross platform migration, just use the default value for
237
+ # nsslapd-idl-switch
238
+ # if not doing cross platform, meaning we just use the existing
239
+ # database binaries, we must preserve whatever the old value is
240
+ # unless migrating from 6.21 or earlier, in which case we must
241
+ # be migrating from LDIF, and must use the new idl switch
242
+ if (!$mig->{crossplatform}) {
243
+ # the given entry is the old entry - see if it has the nsslapd-directory
244
+ my $olddbdir = $ent->getValues('nsslapd-db-home-directory') ||
245
+ $ent->getValues('nsslapd-directory') ||
246
+ "$mig->{actualsroot}/$inst/db"; # old default db home directory
247
+ # replace the old sroot value with the actual physical location on the target/dest
248
+ $olddbdir =~ s/^$mig->{actualsroot}/$mig->{oldsroot}/;
249
+ my @errs;
250
+ my $isold = isOldDatabase($olddbdir, \@errs);
251
+ if (@errs) {
252
+ $mig->msg($FATAL, @errs);
253
+ return $newval; # use default new value
254
+ } elsif ($isold) {
255
+ debug(3, "The database in $olddbdir is too old to migrate the idl switch setting\n");
256
+ return $newval; # use default new value
257
+ }
258
+
259
+ # else the database could be in the new format already - preserve
260
+ # the user's old value
261
+ $newval = $ent->getValues($attr);
262
+ }
263
+
264
+ return $newval;
265
+ }
266
+
267
+ # these are attributes that we have to transform from
268
+ # the old value to the new value (e.g. a pathname)
269
+ # The key of this hash is the attribute name. The value
270
+ # is an anonymous sub which takes two arguments - the entry
271
+ # and the old value. The return value of the sub is
272
+ # the new value
273
+ my %transformAttr =
274
+ (
275
+ 'nsslapd-directory' => \&getNewDbDir,
276
+ 'nsslapd-db-logdirectory' => \&getNewDbDir,
277
+ 'nsslapd-changelogdir' => \&getNewDbDir,
278
+ 'nsds5replicacredentials' => \&migrateCredentials,
279
+ 'nsmultiplexorcredentials' => \&migrateCredentials,
280
+ 'nsstate' => \&removensState,
281
+ 'nsslapd-idl-switch' => \&migIdlSwitch
282
+ );
283
+
284
+ sub copyDatabaseDirs {
285
+ my $srcdir = shift;
286
+ my $destdir = shift;
287
+ my $filesonly = shift;
288
+ my @errs;
289
+
290
+ my $isold = isOldDatabase($srcdir, \@errs);
291
+ if (@errs) {
292
+ return @errs;
293
+ } elsif ($isold) {
294
+ return ('error_database_too_old', $srcdir);
295
+ }
296
+
297
+ if (-d $srcdir && ! -d $destdir && !$filesonly) {
298
+ debug(1, "Copying database directory $srcdir to $destdir\n");
299
+ if (system ("cp -p -r $srcdir $destdir")) {
300
+ return ('error_copying_dbdir', $srcdir, $destdir, $?);
301
+ }
302
+ } elsif (! -d $srcdir) {
303
+ return ("error_dbsrcdir_not_exist", $srcdir);
304
+ } else {
305
+ debug(1, "The destination directory $destdir already exists, copying files/dirs individually\n");
306
+ $! = 0;
307
+ debug(1, "Removing any existing db files in $destdir\n");
308
+ foreach my $file (glob("$destdir/*")) {
309
+ next if (! -f $file);
310
+ unlink($file);
311
+ if ($!) {
312
+ return ("error_removing_temp_db_files", $destdir, $!);
313
+ }
314
+ }
315
+ foreach my $file (glob("$srcdir/*")) {
316
+ if (-f $file) {
317
+ debug(3, "Copying $file to $destdir\n");
318
+ if (system ("cp -p $file $destdir")) {
319
+ return ('error_copying_dbfile', $file, $destdir, $?);
320
+ }
321
+ } elsif (-d $file && !$filesonly) {
322
+ debug(3, "Copying $file to $destdir\n");
323
+ if (system ("cp -p -r $file $destdir")) {
324
+ return ('error_copying_dbdir', $file, $destdir, $?);
325
+ }
326
+ }
327
+ }
328
+ }
329
+
330
+ return ();
331
+ }
332
+
333
+ # older versions may use the old Netscape names e.g. Netscape Administration Server
334
+ # we have to convert these to the new names e.g. 389 Administration Server
335
+ sub migrateNetscapeRoot {
336
+ my $ldiffile = shift;
337
+ my ($fh, $tmpldiffile);
338
+ # create a temp inf file for writing for other processes
339
+ # never overwrite the user supplied inf file
340
+ ($fh, $tmpldiffile) = tempfile("nsrootXXXXXX", UNLINK => 0,
341
+ SUFFIX => ".ldif", OPEN => 1,
342
+ DIR => File::Spec->tmpdir);
343
+ if (!open( MYLDIF, "$ldiffile" )) {
344
+ debug(1, "Error: Can't open $ldiffile: $!");
345
+ return;
346
+ }
347
+ my $in = new Mozilla::LDAP::LDIF(*MYLDIF);
348
+ while (my $ent = readOneEntry $in) {
349
+ my $dn = $ent->getDN();
350
+ next if (!$dn); # netscaperoot should not have the empty dn
351
+ $dn =~ s/\bNetscape\b/389/g;
352
+ $ent->setDN($dn);
353
+ foreach my $attr (keys %{$ent}) {
354
+ my @vals = $ent->getValues($attr);
355
+ map { s/\bNetscape\b/389/g } @vals;
356
+ $ent->setValues($attr, @vals);
357
+ }
358
+ Mozilla::LDAP::LDIF::put_LDIF($fh, 78, $ent);
359
+ }
360
+ close( MYLDIF );
361
+ close( $fh );
362
+
363
+ return $tmpldiffile;
364
+ }
365
+
366
+ sub fixIntegerIndexes {
367
+ my $mig = shift;
368
+ my $inst_dir = shift;
369
+ my $newdbdir = shift;
370
+
371
+ if (!$mig->{integerattrs}) {
372
+ debug(1, "No integer syntax attributes, no indexes fixed\n");
373
+ return ();
374
+ }
375
+
376
+ # look at each index file in the db dir
377
+ # if it is on our list of integer attributes,
378
+ # remove it and re-create it
379
+ my $dbname = basename($newdbdir);
380
+ for (glob("$newdbdir/*.db4")) {
381
+ my $indexname = basename($_, '.db4');
382
+ if ($mig->{integerattrs}->{lc $indexname}) {
383
+ $mig->msg($INFO, 'fixing_integer_attr_index', $indexname, $newdbdir);
384
+ debug(1, "Removing file $_\n");
385
+ if (! unlink $_) {
386
+ debug(1, "Error: could not remove file $_: $!\n");
387
+ return ('error_removing_index_file', $_, $!);
388
+ }
389
+ my $cmd = "$inst_dir/db2index -n \"$dbname\" -t \"$indexname\"";
390
+ debug(1, "Re-creating index file $_: $cmd\n");
391
+ $? = 0; # clear error condition
392
+ my $output = `$cmd 2>&1`;
393
+ if ($?) {
394
+ return ('error_recreating_index_file', $_, $output);
395
+ }
396
+ debug(1, $output);
397
+ } else {
398
+ debug(3, "Index $indexname is not for an integer syntax attribute - skipping\n");
399
+ }
400
+ }
401
+
402
+ return ();
403
+ }
404
+
405
+ # migrate all of the databases in an instance
406
+ sub migrateDatabases {
407
+ my $mig = shift; # the Migration object
408
+ my $inst = shift; # the instance name (e.g. slapd-instance)
409
+ my $src = shift; # a Conn to the source
410
+ my $dest = shift; # a Conn to the dest
411
+ my $olddefault = "$mig->{actualsroot}/$inst/db"; # old default db home directory
412
+ my @errs;
413
+
414
+ # the ldif2db command will be in nsslapd-instancedir
415
+ my $cfgent = $dest->search("cn=config", "base", "(objectclass=*)");
416
+ my $inst_dir = $cfgent->getValues('nsslapd-instancedir');
417
+ # first, look for an LDIF file in that directory with the same name as the
418
+ # database
419
+ my $foundldif;
420
+ for (glob("$mig->{oldsroot}/$inst/db/*.ldif")) {
421
+ my $fname = $_;
422
+ my $dbname = basename($fname, '.ldif');
423
+ my $deleteflag = 0;
424
+ if ($fname =~ /NetscapeRoot.ldif$/) {
425
+ $fname = migrateNetscapeRoot($fname);
426
+ if ($fname) {
427
+ # make sure $fname is owned by the server user
428
+ my $cfgent = $dest->search("cn=config", "base", "(objectclass=*)");
429
+ my $user = $cfgent->getValues('nsslapd-localuser');
430
+ my $uid = getpwnam $user;
431
+ chown $uid, -1, $fname;
432
+ $deleteflag = 1;
433
+ } else {
434
+ return ("error_creating_templdif", $!);
435
+ }
436
+ }
437
+ my $cmd = "$inst_dir/ldif2db -n \"$dbname\" -i \"$fname\"";
438
+ debug(1, "migrateDatabases: executing command $cmd\n");
439
+ $? = 0; # clear error condition
440
+ my $output = `$cmd 2>&1`;
441
+ if ($deleteflag) {
442
+ unlink($fname);
443
+ }
444
+ if ($?) {
445
+ return ('error_importing_migrated_db', $fname, $?, $output);
446
+ }
447
+ debug(1, $output);
448
+ $foundldif = 1;
449
+ }
450
+
451
+ if ($foundldif) {
452
+ return (); # done - can do nothing else for cross-platform
453
+ } elsif ($mig->{crossplatform}) { # cross platform requires LDIF files
454
+ return ('ldif_required_for_cross_platform', "$mig->{oldsroot}/$inst/db");
455
+ }
456
+
457
+ # if no LDIF files, just copy over the database directories
458
+ my $ent = $src->search("cn=ldbm database,cn=plugins,cn=config", "one",
459
+ "(objectclass=*)");
460
+ if (!$ent) {
461
+ return ("error_reading_olddbconfig", $src->getErrorString());
462
+ }
463
+ # there is one case where we want to just use the existing db directory
464
+ # that's the case where the user has moved the indexes and/or the
465
+ # transaction logs to different partitions for performance
466
+ # in that case, the old directory will not be the same as the default,
467
+ # and the directory will exist
468
+ my $olddefault = "$mig->{actualsroot}/$inst";
469
+ do {
470
+ my $cn = $ent->getValues('cn');
471
+ my %objclasses = map { lc($_) => $_ } $ent->getValues('objectclass');
472
+ if ($cn eq 'config') { # global config
473
+ my $newent = $dest->search($ent->getDN(), "base", "(objectclass=*)");
474
+ my $newdbdir = "";
475
+ if ("") {
476
+ $newdbdir = $newent->getValues('nsslapd-directory') ||
477
+ "/var/$mig->{pkgname}/$inst/db";
478
+ } else {
479
+ $newdbdir = $newent->getValues('nsslapd-directory') ||
480
+ "/var/lib/$mig->{pkgname}/$inst/db";
481
+ }
482
+ debug(1, "Found ldbm database plugin config entry ", $ent->getDN(), "\n");
483
+ my $dir = $ent->getValues('nsslapd-directory');
484
+ my $homedir = $ent->getValues('nsslapd-db-home-directory');
485
+ my $logdir = $ent->getValues('nsslapd-db-logdirectory');
486
+ debug(1, "old db dir = $dir homedir = $homedir logdir = $logdir\n");
487
+ my $srcdir = $homedir || $dir || "$olddefault/db";
488
+ if (-d $srcdir and ($srcdir !~ /^$olddefault/)) {
489
+ debug(2, "Not copying database files from [$srcdir]\n");
490
+ } else {
491
+ # replace the old sroot value with the actual physical location on the target/dest
492
+ $srcdir =~ s/^$mig->{actualsroot}/$mig->{oldsroot}/;
493
+ if (@errs = copyDatabaseDirs($srcdir, $newdbdir, 1)) {
494
+ return @errs;
495
+ }
496
+ }
497
+ if ($logdir && ($logdir ne $srcdir)) {
498
+ if (-d $logdir and ($logdir !~ /^$olddefault/)) {
499
+ debug(2, "Not copying transaction logs from [$logdir]\n");
500
+ } else {
501
+ # replace the old sroot value with the actual physical location on the target/dest
502
+ $newdbdir = $newent->getValues('nsslapd-db-logdirectory') ||
503
+ $newdbdir;
504
+ $logdir =~ s/^$mig->{actualsroot}/$mig->{oldsroot}/;
505
+ if (@errs = copyDatabaseDirs($logdir, $newdbdir, 1)) {
506
+ return @errs;
507
+ }
508
+ }
509
+ }
510
+ } elsif ($objclasses{nsbackendinstance}) {
511
+ debug(1, "Found ldbm database instance entry ", $ent->getDN(), "\n");
512
+ my $dir = $ent->getValues('nsslapd-directory');
513
+ # the default db instance directory is
514
+ # $oldroot/$inst/$cn
515
+ debug(1, "old instance $cn dbdir $dir\n");
516
+ my $srcdir = $dir || "$olddefault/db/$cn";
517
+ my $newent = $dest->search($ent->getDN(), "base", "(objectclass=*)");
518
+ my $newdbdir = "";
519
+ if ("") {
520
+ $newdbdir = $newent->getValues('nsslapd-directory') ||
521
+ "/var/$mig->{pkgname}/$inst/db/$cn";
522
+ } else {
523
+ $newdbdir = $newent->getValues('nsslapd-directory') ||
524
+ "/var/lib/$mig->{pkgname}/$inst/db/$cn";
525
+ }
526
+ if (-d $srcdir and ($srcdir !~ /^$olddefault/)) {
527
+ debug(2, "Not copying database indexes from [$srcdir]\n");
528
+ } else {
529
+ # replace the old sroot value with the actual physical location on the target/dest
530
+ $srcdir =~ s/^$mig->{actualsroot}/$mig->{oldsroot}/;
531
+ if (@errs = copyDatabaseDirs($srcdir, "$newdbdir")) {
532
+ return @errs;
533
+ }
534
+ # fix up the integer indexes
535
+ if ($mig->{integerattrs}) {
536
+ debug(3, "The schema has some integer attributes\n");
537
+ if (@errs = fixIntegerIndexes($mig, $inst_dir, $newdbdir)) {
538
+ return @errs;
539
+ }
540
+ } else {
541
+ debug(3, "No integer attributes to fix for $newdbdir\n");
542
+ }
543
+ }
544
+ }
545
+ } while ($ent = $src->nextEntry());
546
+
547
+ return ();
548
+ }
549
+
550
+ sub migrateChangelogs {
551
+ my $mig = shift; # the Migration object
552
+ my $inst = shift; # the instance name (e.g. slapd-instance)
553
+ my $src = shift; # a Conn to the source
554
+ my $dest = shift; # a Conn to the dest
555
+ my $olddefault = "$mig->{actualsroot}/$inst"; # old default db home directory
556
+ # changelog config entry
557
+ my $oldent = $src->search("cn=changelog5, cn=config", "base", "(objectclass=*)");
558
+ my $newent = $dest->search("cn=changelog5, cn=config", "base", "(objectclass=*)");
559
+ if ($oldent and $newent) { # changelog configured
560
+ my $oldcldir = $oldent->getValues('nsslapd-changelogdir');
561
+ if (-d $oldcldir and ($oldcldir !~ /^$olddefault/)) {
562
+ debug(2, "Not copying changelogdb from [$oldcldir]\n");
563
+ } else {
564
+ # replace the old sroot value with the actual physical location on the target/dest
565
+ $oldcldir =~ s/^$mig->{actualsroot}/$mig->{oldsroot}/;
566
+ my $newcldir = $newent->getValues('nsslapd-changelogdir');
567
+ my @errs = copyDatabaseDirs($oldcldir, $newcldir);
568
+ if (@errs) {
569
+ return @errs;
570
+ }
571
+ }
572
+ }
573
+
574
+ return ();
575
+ }
576
+
577
+ sub fixAttrsInEntry {
578
+ my ($ent, $mig, $inst) = @_;
579
+ for my $attr (keys %{$ent}) {
580
+ my $lcattr = lc $attr;
581
+ if ($ignoreOld{$lcattr}) {
582
+ debug(3, "fixAttrsInEntry: ignoring old invalid or obsolete attr $attr\n");
583
+ $ent->remove($attr);
584
+ next;
585
+ } elsif ($transformAttr{$lcattr}) {
586
+ my $newval = &{$transformAttr{$lcattr}}($ent, $attr, $mig, $inst);
587
+ if (!$newval) {
588
+ debug(2, "Removing attribute $attr from entry ", $ent->getDN(), "\n");
589
+ $ent->remove($attr);
590
+ } else {
591
+ debug(2, "Setting new value $newval for attribute $attr in entry ", $ent->getDN(), "\n");
592
+ $ent->setValues($attr, $newval);
593
+ }
594
+ } # else just keep as is
595
+ }
596
+ }
597
+
598
+ sub mergeEntries {
599
+ my ($old, $new, $mig, $inst) = @_;
600
+ my %inoldonly; # attrs in old entry but not new one
601
+ my %innewonly; # attrs in new entry but not old one
602
+ my @attrs; # attrs common to old and new
603
+ # if the attribute exists in the old entry but not the new one
604
+ # we should probably add it (checking for special cases first)
605
+ # if the attribute exists in the new entry but not the old one
606
+ # we might have to delete it from the new entry
607
+ # first, get a list of all attributes
608
+ foreach my $attr (keys %{$old}) {
609
+ if (! $new->exists($attr)) {
610
+ $inoldonly{$attr} = $attr;
611
+ } else {
612
+ push @attrs, $attr;
613
+ }
614
+ }
615
+ foreach my $attr (keys %{$new}) {
616
+ if (! $old->exists($attr)) {
617
+ $innewonly{$attr} = $attr;
618
+ }
619
+ }
620
+
621
+ # iterate through the attr lists
622
+ my $cn = lc $new->getValues("cn");
623
+ foreach my $attr (keys %inoldonly, keys %innewonly, @attrs) {
624
+ debug(3, "mergeEntries: merging entry ", $old->getDN(), " attr $attr\n");
625
+ my $lcattr = lc $attr;
626
+ if ($ignoreOld{$lcattr}) {
627
+ debug(3, "mergeEntries: ignoring old invalid or obsolete attr $attr\n");
628
+ next; # use new value or just omit if attr is obsolete
629
+ } elsif ($transformAttr{$lcattr}) {
630
+ # only transform if the value is in the old entry
631
+ if (!$innewonly{$attr}) {
632
+ my $oldval = $old->getValues($attr);
633
+ my $newval = &{$transformAttr{$lcattr}}($old, $attr, $mig, $inst);
634
+ if (!$newval) {
635
+ debug(3, "Removing attribute $attr from entry ", $new->getDN(), "\n");
636
+ $new->remove($attr);
637
+ } else {
638
+ debug(3, "Setting new value $newval for attribute $attr in entry ", $new->getDN(), "\n");
639
+ $new->setValues($attr, $newval);
640
+ }
641
+ }
642
+ } elsif ($cn eq "internationalization plugin" and $lcattr eq "nsslapd-pluginarg0") {
643
+ debug(3, "mergeEntries: using new value of internationalization plugin nsslapd-pluginarg0\n");
644
+ next; # use the new value of this path name
645
+ } elsif ($cn eq "referential integrity postoperation" and $lcattr eq "nsslapd-pluginarg1") {
646
+ debug(3, "mergeEntries: using new value of referential integrity postoperation nsslapd-pluginarg1\n");
647
+ next; # use the new value of this path name
648
+ } elsif ($innewonly{$attr}) {
649
+ debug(3, "mergeEntries: removing attr $attr from new entry\n");
650
+ $new->remove($attr); # in new but not old - just remove it
651
+ } else {
652
+ my $oldval = $old->getValues($attr);
653
+ my $newval = $new->getValues($attr);
654
+ $new->setValues($attr, $old->getValues($attr)); # use old value
655
+ debug(3, "mergeEntries: using old val $oldval instead of new val $newval\n");
656
+ }
657
+ }
658
+ }
659
+
660
+ my @allattrlist = ('*', 'aci', 'createTimestamp', 'creatorsName',
661
+ 'modifyTimestamp', 'modifiersName');
662
+
663
+ sub getAllEntries {
664
+ my $conn = shift;
665
+ my $href = shift;
666
+ my $aref = shift;
667
+
668
+ # these are the special DSEs for which we only need ACIs
669
+ for my $dn ("", "cn=monitor", "cn=config") {
670
+ my $scope = $dn ? "sub" : "base";
671
+ my @attrlist;
672
+ if ($dn eq "cn=config") {
673
+ @attrlist = @allattrlist;
674
+ } else {
675
+ @attrlist = qw(aci);
676
+ }
677
+ my $ent = $conn->search($dn, $scope, "(objectclass=*)", 0, @attrlist);
678
+ next if (!$ent or ($conn->getErrorCode() eq 32));
679
+ if ($conn->getErrorCode()) {
680
+ return ('error_reading_entry', $dn, $conn->getErrorString());
681
+ }
682
+ do {
683
+ my $ndn = normalizeDN($ent->getDN());
684
+ $href->{$ndn} = $ent;
685
+ push @{$aref}, $ndn;
686
+ } while ($ent = $conn->nextEntry());
687
+ }
688
+
689
+ return ();
690
+ }
691
+
692
+ # these entries cannot be migrated if doing cross platform
693
+ my %noCrossPlatformDN = (
694
+ 'cn=uniqueid generator,cn=config' => 'cn=uniqueid generator,cn=config'
695
+ );
696
+
697
+ sub mergeConfigEntries {
698
+ my $mig = shift; # the Migration object
699
+ my $inst = shift; # the instance name (e.g. slapd-instance)
700
+ my $src = shift; # a Conn to the source
701
+ my $dest = shift; # a Conn to the dest
702
+
703
+ # first, read in old file
704
+ my %olddse; # map of normalized DN to Entry
705
+ my @olddns; # the DNs in their original order
706
+ my @errs;
707
+ if (@errs = getAllEntries($src, \%olddse, \@olddns)) {
708
+ return @errs;
709
+ }
710
+
711
+ # next, read in new file
712
+ my %newdse; # map of normalized DN to Entry
713
+ my @allnewdns;
714
+ my @newdns; # the DNs in their original order that are not in olddns
715
+ if (@errs = getAllEntries($dest, \%newdse, \@allnewdns)) {
716
+ return @errs;
717
+ }
718
+
719
+ for my $ndn (@allnewdns) {
720
+ if (! exists $olddse{$ndn}) {
721
+ push @newdns, $ndn;
722
+ }
723
+ }
724
+
725
+ # now, compare entries
726
+ # if the entry exists in the old tree but not the new, add it
727
+ # if the entry exists in the new tree but not the old, delete it
728
+ # otherwise, merge the entries
729
+ # @olddns contains the dns in the old dse.ldif, including ones that
730
+ # may also be in the new dse.ldif
731
+ # @newdns contains dns that are only in the new dse.ldif
732
+ for my $dn (@olddns, @newdns) {
733
+ my $oldent = $olddse{$dn};
734
+ my $newent = $newdse{$dn};
735
+ my $op;
736
+ my $rc = 1;
737
+ if ($mig->{crossplatform} && $noCrossPlatformDN{$dn}) {
738
+ debug(1, "Cannot migrate the entry $dn - skipping\n");
739
+ next;
740
+ } elsif ($oldent && !$newent) {
741
+ if (!$ignoreOldEntries{$dn}) { # make sure it's not obsolete
742
+ # may have to fix up some values in the old entry
743
+ fixAttrsInEntry($oldent, $mig, $inst);
744
+ $rc = $dest->add($oldent);
745
+ $op = "add";
746
+ } else {
747
+ debug(2, "Ignoring entry $dn - configuration not supported\n");
748
+ }
749
+ } elsif (!$oldent && $newent) {
750
+ if ($dn =~ /o=deleteAfterMigration/i) {
751
+ $rc = $dest->delete($dn);
752
+ $op = "delete";
753
+ } else {
754
+ # do nothing - no change to entry
755
+ }
756
+ } else { #merge
757
+ # $newent will contain the merged entry
758
+ mergeEntries($oldent, $newent, $mig, $inst);
759
+ $rc = $dest->update($newent);
760
+ $op = "update";
761
+ }
762
+
763
+ if (!$rc) {
764
+ return ('error_updating_merge_entry', $op, $dn, $dest->getErrorString());
765
+ }
766
+ }
767
+
768
+ return ();
769
+ }
770
+
771
+ my %deletedschema = (
772
+ '50ns-calendar' => '50ns-calendar.ldif',
773
+ '50ns-compass' => '50ns-compass.ldif',
774
+ '50ns-delegated-admin' => '50ns-delegated-admin.ldif',
775
+ '50ns-legacy' => '50ns-legacy.ldif',
776
+ '50ns-mail' => '50ns-mail.ldif',
777
+ '50ns-mcd-browser' => '50ns-mcd-browser.ldif',
778
+ '50ns-mcd-config' => '50ns-mcd-config.ldif',
779
+ '50ns-mcd-li' => '50ns-mcd-li.ldif',
780
+ '50ns-mcd-mail' => '50ns-mcd-mail.ldif',
781
+ '50ns-media' => '50ns-media.ldif',
782
+ '50ns-mlm' => '50ns-mlm.ldif',
783
+ '50ns-msg' => '50ns-msg.ldif',
784
+ '50ns-netshare' => '50ns-netshare.ldif',
785
+ '50ns-news' => '50ns-news.ldif',
786
+ '50ns-proxy' => '50ns-proxy.ldif',
787
+ '50ns-wcal' => '50ns-wcal.ldif',
788
+ '51ns-calendar' => '51ns-calendar.ldif'
789
+ );
790
+
791
+ # these indexes are handled specially by the db code
792
+ my %intattrstoskip = (
793
+ 'numsubordinates' => 'numSubordinates',
794
+ 'hassubordinates' => 'hasSubordinates'
795
+ );
796
+
797
+ sub fixup99user {
798
+ my $mig = shift; # the Migration object
799
+ my $inst = shift; # The name of the instance
800
+ my $newschemadir = shift; # the new instance's schema path
801
+
802
+ my %attrstoskip = ();
803
+ my %objclassestoskip = ();
804
+ my $uid;
805
+ my $gid;
806
+ my $mode;
807
+
808
+ # Read every schema file in the legacy server's schema directory
809
+ for (glob("$mig->{oldsroot}/$inst/config/schema/*.ldif")) {
810
+ if (!open( OLDSCHEMA, $_ )) {
811
+ debug(0, "Can't open schema file $_: $!\n");
812
+ next;
813
+ }
814
+
815
+ # Read attributes from each file, looking for ones that contain
816
+ # the string "DESC ''".
817
+ my $in = new Mozilla::LDAP::LDIF(*OLDSCHEMA);
818
+ while (my $ent = readOneEntry $in) {
819
+ my @attrs = $ent->getValues('attributeTypes');
820
+ my @objclasses = $ent->getValues('objectClasses');
821
+ foreach my $attr (@attrs) {
822
+ debug(4, "Checking if attribute should be added to skip list ($attr)\n");
823
+ if ($attr =~ /\(\s*(\S*)\s*NAME .* DESC \'\'/) {
824
+ # Store the OID of those in an associative array for
825
+ # quick lookups later.
826
+ debug(3, "Adding attribute to list to skip (OID $1)\n");
827
+ $attrstoskip{"$1"} = 1;
828
+ }
829
+ }
830
+
831
+ foreach my $objclass (@objclasses) {
832
+ debug(4, "Checking if objectclass should be added to skip list ($objclass)\n");
833
+ if ($objclass =~ /\(\s*(\S*)\s*NAME .* DESC \'\'/) {
834
+ # Store the OID of those in an associative array for
835
+ # quick lookups later.
836
+ debug(3, "Adding objectclass to list to skip (OID $1)\n");
837
+ $objclassestoskip{"$1"} = 1;
838
+ }
839
+ }
840
+ }
841
+
842
+ close(OLDSCHEMA);
843
+ }
844
+
845
+ # Open the 99user.ldif file in the new server schema directory, which is a
846
+ # copy of the one in the legacy server. Also open a tempfile.
847
+ if (!open(USERSCHEMA, "$newschemadir/99user.ldif")) {
848
+ return ("error_opening_schema", "$newschemadir/99user.ldif", $!);
849
+ }
850
+
851
+ # Open a tempfile to write the cleaned 99user.ldif to
852
+ if (!open(TMPSCHEMA, ">$newschemadir/99user.ldif.tmp")) {
853
+ close(USERSCHEMA);
854
+ return ("error_opening_schema", "$newschemadir/99user.ldif.tmp", $!);
855
+ }
856
+
857
+ # Iterate through every attribute in the 99user.ldif file and write them to the
858
+ # tempfile if their OID doesn't exist in the "bad schema" array.
859
+ my $in = new Mozilla::LDAP::LDIF(*USERSCHEMA);
860
+ while (my $ent = readOneEntry $in) {
861
+ my @attrs = $ent->getValues('attributeTypes');
862
+ my @objclasses = $ent->getValues('objectClasses');
863
+ my @keepattrs;
864
+ my @keepobjclasses;
865
+ foreach my $attr (@attrs) {
866
+ if ($attr =~ /\(\s*(\S*)\s*NAME/) {
867
+ debug(3, "Checking if attribute should be trimmed (OID $1)\n");
868
+ # See if this OID is in our list of attrs to skip
869
+ if ($attrstoskip{"$1"}) {
870
+ debug(2, "Trimming attribute from 99user.ldif (OID $1)\n");
871
+ next;
872
+ }
873
+ }
874
+
875
+ # Keep this value
876
+ debug(3, "Keeping attribute in 99user.ldif (OID $1)\n");
877
+ push @keepattrs, $attr;
878
+ }
879
+
880
+ foreach my $objclass (@objclasses) {
881
+ if ($objclass =~ /\(\s*(\S*)\s*NAME/) {
882
+ debug(3, "Checking if objectclass should be trimmed (OID $1)\n");
883
+ # See if this OID is in our list of objectclasses to skip
884
+ if ($objclassestoskip{"$1"}) {
885
+ debug(2, "Trimming objectclass from 99user.ldif (OID $1)\n");
886
+ next;
887
+ }
888
+ }
889
+
890
+ # Keep this value
891
+ debug(3, "Keeping objectclass in 99user.ldif (OID $1)\n");
892
+ push @keepobjclasses, $objclass;
893
+ }
894
+
895
+ # Update the entry with the values we want to keep
896
+ if ($#keepattrs >= $[) {
897
+ $ent->setValues("attributetypes", @keepattrs);
898
+ } else {
899
+ $ent->remove("attributetypes");
900
+ }
901
+
902
+ if ($#keepobjclasses >= $[) {
903
+ $ent->setValues("objectclasses", @keepobjclasses);
904
+ } else {
905
+ $ent->remove("objectclasses");
906
+ }
907
+
908
+ # Write the entry to temp schema file
909
+ my $oldfh = select(TMPSCHEMA);
910
+ $ent->printLDIF();
911
+ select($oldfh);
912
+ }
913
+
914
+ close(USERSCHEMA);
915
+ close(TMPSCHEMA);
916
+
917
+ # Make the ownership and permissions on the temp schema file
918
+ # the same as the copied 99user.ldif.
919
+ ($mode, $uid, $gid) = (stat("$newschemadir/99user.ldif"))[2,4,5];
920
+ if ((chown $uid, $gid, "$newschemadir/99user.ldif.tmp") != 1) {
921
+ return ("error_schema_permissions", "$newschemadir/99user.ldif.tmp", $!);
922
+ }
923
+
924
+ if ((chmod $mode, "$newschemadir/99user.ldif.tmp") != 1) {
925
+ return ("error_schema_permissions", "$newschemadir/99user.ldif.tmp", $!);
926
+ }
927
+
928
+ # Replace the copied 99user.ldif with the trimmed file.
929
+ if ((rename "$newschemadir/99user.ldif.tmp", "$newschemadir/99user.ldif") != 1) {
930
+ return ("error_renaming_schema", "$newschemadir/99user.ldif.tmp", "$newschemadir/99user.ldif", $!);
931
+ }
932
+
933
+ return();
934
+ }
935
+
936
+ sub migrateSchema {
937
+ my $mig = shift; # the Migration object
938
+ my $inst = shift; # the instance name (e.g. slapd-instance)
939
+ my $src = shift; # a Conn to the source
940
+ my $dest = shift; # a Conn to the dest
941
+
942
+ my @errs;
943
+ my $cfgent = $dest->search("cn=config", "base", "(objectclass=*)");
944
+ my $newschemadir = $cfgent->getValues('nsslapd-schemadir') ||
945
+ "$mig->{configdir}/$inst/schema";
946
+ my %newschema = map {basename($_, '.ldif') => $_} glob("$newschemadir/*.ldif");
947
+ delete $newschema{"99user"}; # always copy this one
948
+ for (glob("$mig->{oldsroot}/$inst/config/schema/*.ldif")) {
949
+ my $fname = basename($_, '.ldif');
950
+ next if ($deletedschema{$fname}); # don't copy deleted schema
951
+ next if ($newschema{$fname}); # use new version
952
+ if (system("cp -p $_ $newschemadir")) {
953
+ return ("error_migrating_schema", $_, $!);
954
+ }
955
+ }
956
+
957
+ # fixup any attributes with missing descriptions in 99user.ldif
958
+ if (@errs = fixup99user($mig, $inst, $newschemadir)) {
959
+ return @errs;
960
+ }
961
+
962
+ if (!$mig->{crossplatform}) {
963
+ # now, for all of the new schema, we need to get the list of attribute
964
+ # types with INTEGER syntax, including derived types (e.g. SUP 'attr')
965
+ # not required for cross platform because import of the old ldif file
966
+ # will automatically recreate all indexes
967
+ my %intattrs = ();
968
+ for (glob("$newschemadir/*.ldif")) {
969
+ # read in schema entry from LDIF
970
+ if (!open( MYSCHEMA, $_ )) {
971
+ debug(0, "Can't open schema file $_: $!\n");
972
+ next;
973
+ }
974
+ my $in = new Mozilla::LDAP::LDIF(*MYSCHEMA);
975
+ while (my $ent = readOneEntry $in) {
976
+ my @attrs = $ent->getValues('attributeTypes');
977
+ foreach my $attr (@attrs) {
978
+ # first see if the attribute definition uses INTEGER syntax
979
+ # else see if the super uses INTEGER - note this assumes the attributes
980
+ # are listed in the files in SUP order - that is, an attribute does
981
+ # not reference a SUP before it is defined
982
+ if ($attr =~ / NAME (?:\(\s)?[\']?(\w+)[\']?.* SYNTAX 1.3.6.1.4.1.1466.115.121.1.27[\{\s]/) {
983
+ next if ($intattrstoskip{lc $1});
984
+ $intattrs{lc $1} = $1;
985
+ } elsif (($attr =~ / NAME (?:\(\s)?[\']?(\w+)[\']?.*SUP [\']?(\w+)[\']?/) &&
986
+ $intattrs{lc $2}) {
987
+ next if ($intattrstoskip{lc $1});
988
+ $intattrs{lc $1} = $1;
989
+ }
990
+ }
991
+ }
992
+ close MYSCHEMA;
993
+ }
994
+ # %intattrs now contains all of the integer valued attributes
995
+ $mig->{integerattrs} = \%intattrs; # hashref
996
+ }
997
+
998
+ return ();
999
+ }
1000
+
1001
+ sub migrateDSInstance {
1002
+ my $mig = shift; # the Migration object
1003
+ my $inst = shift; # the instance name (e.g. slapd-instance)
1004
+ my $src = shift; # a Conn to the source
1005
+ my $dest = shift; # a Conn to the dest
1006
+
1007
+ my @errs;
1008
+ # first, merge dse ldif
1009
+ if (@errs = mergeConfigEntries($mig, $inst, $src, $dest)) {
1010
+ return @errs;
1011
+ }
1012
+
1013
+ # next, grab the old schema
1014
+ if (@errs = migrateSchema($mig, $inst, $src, $dest)) {
1015
+ return @errs;
1016
+ }
1017
+
1018
+ if (@errs = updateDS($mig)) {
1019
+ return @errs;
1020
+ }
1021
+
1022
+ # next, the databases
1023
+ if (@errs = migrateDatabases($mig, $inst, $src, $dest)) {
1024
+ return @errs;
1025
+ }
1026
+
1027
+ # next, the changelogs
1028
+ if (!$mig->{crossplatform}) {
1029
+ if (@errs = migrateChangelogs($mig, $inst, $src, $dest)) {
1030
+ return @errs;
1031
+ }
1032
+ }
1033
+
1034
+ # next, the security files
1035
+ my $cfgent = $dest->search("cn=config", "base", "(objectclass=*)");
1036
+ my $newcertdir = $cfgent->getValues("nsslapd-certdir") ||
1037
+ "/etc/dirsrv/$inst";
1038
+ $mig->migrateSecurityFiles($inst, $newcertdir);
1039
+
1040
+ return @errs;
1041
+ }
1042
+
1043
+ sub migrateDS {
1044
+ my $mig = shift;
1045
+ my @errs;
1046
+
1047
+ # migration needs to know the instance directory for the directory
1048
+ # servers - this assumes they are all in the same place
1049
+ if (!$mig->{ServerRoot}) {
1050
+ if ("") {
1051
+ $mig->{ServerRoot} = "$mig->{inf}->{General}->{prefix}/opt/dirsrv";
1052
+ } else {
1053
+ $mig->{ServerRoot} = "$mig->{inf}->{General}->{prefix}/usr/lib64/dirsrv";
1054
+ }
1055
+ }
1056
+
1057
+ # for each instance
1058
+ foreach my $inst (@{$mig->{instances}}) {
1059
+ if (-f "$mig->{configdir}/$inst/dse.ldif") {
1060
+ $mig->msg($WARN, 'instance_already_exists', "$mig->{configdir}/$inst/dse.ldif");
1061
+ next;
1062
+ }
1063
+
1064
+ # you could theoretically make this work with either a remote source or
1065
+ # remote dest
1066
+ # $mig->{inf} would contain an entry for each instance e.g.
1067
+ # $mig->{inf}->{$inst}
1068
+ # each instance specific entry would contain a {General} and a {slapd}
1069
+ # all the information necessary to open an LDAP::Conn to the server
1070
+ # if the source, you could also change createInfFromConfig to read
1071
+ # the info from the Conn (or FileConn) that's needed to create the
1072
+ # instance on the dest
1073
+
1074
+ # extract the information needed for ds_newinst.pl
1075
+ my $oldconfigdir = "$mig->{oldsroot}/$inst/config";
1076
+ my $inf = createInfFromConfig($oldconfigdir, $inst, \@errs);
1077
+ if (@errs) {
1078
+ $mig->msg(@errs);
1079
+ return 0;
1080
+ }
1081
+ if (!$inf) {
1082
+ $mig->msg($FATAL, 'error_opening_dseldif', "$oldconfigdir/dse.ldif", $!);
1083
+ return 0;
1084
+ }
1085
+ debug(2, "Using inf created from $oldconfigdir\n");
1086
+
1087
+ # create servers but do not start them until after databases
1088
+ # have been migrated
1089
+ $inf->{slapd}->{start_server} = 0;
1090
+
1091
+ # create the new instance
1092
+ @errs = createDSInstance($inf);
1093
+ if ($inf->{filename}) {
1094
+ unlink($inf->{filename});
1095
+ }
1096
+ if (@errs) {
1097
+ $mig->msg(@errs);
1098
+ $mig->msg($FATAL, 'error_creating_dsinstance', $inst);
1099
+ goto cleanup;
1100
+ } else {
1101
+ $mig->msg('created_dsinstance', $inst);
1102
+ }
1103
+
1104
+ my $src = new FileConn("$oldconfigdir/dse.ldif", 1); # read-only
1105
+ if (!$src) {
1106
+ $mig->msg($FATAL, 'error_opening_dseldif', "$oldconfigdir/dse.ldif", $!);
1107
+ goto cleanup;
1108
+ }
1109
+ my $dest = new FileConn("$mig->{configdir}/$inst/dse.ldif");
1110
+ if (!$dest) {
1111
+ $src->close();
1112
+ $mig->msg($FATAL, 'error_opening_dseldif', "$mig->{configdir}/$inst/dse.ldif", $!);
1113
+ goto cleanup;
1114
+ }
1115
+
1116
+ @errs = migrateDSInstance($mig, $inst, $src, $dest);
1117
+ $src->close();
1118
+ $dest->close();
1119
+ if (@errs) {
1120
+ $mig->msg(@errs);
1121
+ goto cleanup;
1122
+ }
1123
+
1124
+ # ensure any selinux relabeling gets done if needed
1125
+ DSCreate::updateSelinuxPolicy($inf);
1126
+
1127
+ # do the tmpfiles.d stuff
1128
+ @errs = DSCreate::updateTmpfilesDotD($inf);
1129
+ if (@errs) {
1130
+ $mig->msg(@errs);
1131
+ goto cleanup;
1132
+ }
1133
+
1134
+ # do the systemd stuff
1135
+ @errs = DSCreate::updateSystemD(0, $inf);
1136
+ if (@errs) {
1137
+ $mig->msg(@errs);
1138
+ goto cleanup;
1139
+ }
1140
+
1141
+ # finally, start the server
1142
+ if ($mig->{start_servers}) {
1143
+ $inf->{slapd}->{start_server} = 1;
1144
+ if (@errs = DSCreate::startServer($inf)) {
1145
+ $mig->msg(@errs);
1146
+ goto cleanup;
1147
+ }
1148
+ }
1149
+
1150
+ next;
1151
+
1152
+ cleanup:
1153
+ if (-d "$mig->{configdir}/$inst") {
1154
+ @errs = removeDSInstance($inf->{slapd}->{ServerIdentifier}, 1, "" ,"", $mig->{inf}->{General}->{prefix} );
1155
+ if (@errs) {
1156
+ $mig->msg(@errs);
1157
+ }
1158
+ }
1159
+ return 0;
1160
+ }
1161
+
1162
+ return 1;
1163
+ }
1164
+
1165
+ #############################################################################
1166
+ # Mandatory TRUE return value.
1167
+ #
1168
+ 1;
1169
+
1170
+ # emacs settings
1171
+ # Local Variables:
1172
+ # mode:perl
1173
+ # indent-tabs-mode: nil
1174
+ # tab-width: 4
1175
+ # End: