2 $Version = 'SCST DB Configurator v0.51';
6 # Written by Mark R. Buechler 12/07/04
15 -config <config> : Configure SCST given the specified configuration file.
16 -check : Check database configuration against current configuration.
19 -ForceConfig : Force all confuration changes, even deletions (DANGER!).
21 Debugging (limited support)
22 -debug : Debug mode - don\'t do anything destructive.
26 scst_db config scst_db.conf
39 my $_DEF_CONFIG_ = '/etc/scst_db.conf';
45 my $_DEFAULT_GROUP_ = 'Default';
47 my $_MDADM_ = '/sbin/mdadm';
48 my $_MDSTAT_ = '/proc/mdstat';
49 my $_MD_DEV_ = '/dev/';
61 my %_HANDLER_MAP_ = ('cdrom' => $SCST::SCST::CDROM_TYPE,
62 'changer' => $SCST::SCST::CHANGER_TYPE,
63 'disk' => $SCST::SCST::DISK_TYPE,
64 'disk_fileio' => $SCST::SCST::DISKFILE_TYPE,
65 'cdrom_fileio' => $SCST::SCST::CDROMFILE_TYPE,
66 'disk_perf' => $SCST::SCST::DISKPERF_TYPE,
67 'modisk' => $SCST::SCST::MODISK_TYPE,
68 'modisk_perf' => $SCST::SCST::MODISKPERF_TYPE,
69 'tape' => $SCST::SCST::TAPE_TYPE,
70 'tape_perf' => $SCST::SCST::TAPEPERF_TYPE);
72 my %_REVERSE_MAP_ = ($SCST::SCST::CDROM_TYPE => 'cdrom',
73 $SCST::SCST::CHANGER_TYPE => 'changer',
74 $SCST::SCST::DISK_TYPE => 'disk',
75 $SCST::SCST::DISKFILE_TYPE => 'disk_fileio',
76 $SCST::SCST::CDROMFILE_TYPE => 'cdrom_fileio',
77 $SCST::SCST::DISKPERF_TYPE => 'disk_perf',
78 $SCST::SCST::MODISK_TYPE => 'modisk',
79 $SCST::SCST::MODISKPERF_TYPE => 'modisk_perf',
80 $SCST::SCST::TAPE_TYPE => 'tape',
81 $SCST::SCST::TAPEPERF_TYPE => 'tape_perf');
83 $SIG{INT} = \&commitSuicide;
94 my $p = new Getopt::Long::Parser;
96 if (!$p->getoptions('config:s' => \$applyConfig,
97 'check' => \$checkConfig,
98 'ForceConfig' => \$forceConfig,
99 'debug' => \$_DEBUG_)) {
103 $applyConfig = $_DEF_CONFIG_ if (defined($applyConfig) && !$applyConfig);
104 $forceConfig = $TRUE if (defined($forceConfig));
106 return ($applyConfig, $checkConfig, $forceConfig);
112 STDOUT->autoflush(1);
114 # We need to run as root
115 if ( $> ) {die("This program must run as root.\n");}
117 my ($config, $check, $force) = getArgs();
119 $SCST = new SCST::SCST($_DEBUG_);
126 $rc = applyConfiguration($config, $force, $check);
130 print "No valid operations specified.\n";
140 sub readCurrentConfig {
141 print "Collecting current configuration.. ";
143 my $eHandlers = $SCST->handlers();
145 foreach my $handler (@{$eHandlers}) {
146 $HANDLERS{$handler}++; # For quick lookups
149 $DEVICES = $SCST->devices();
150 my $_eGroups = $SCST->groups();
152 foreach my $group (@{$_eGroups}) {
153 $GROUPS{$group}++; # For quick lookups
154 $ASSIGNMENTS{$group} = $SCST->groupDevices($group);
155 my $eUsers = $SCST->users($group);
157 foreach my $user (@{$eUsers}) {
158 $USERS{$group}->{$user}++; # For quick lookups
166 my $ch = new IO::Handle;
168 print "Scanning available system devices.. ";
170 my $mdstat = new IO::File $_MDSTAT_, O_RDONLY;
172 die("FATAL: Unable to gather a list of available md devices.\n") if (!$mdstat);
174 while (my $line = <$mdstat>) {
175 if ($line =~ /^md/) {
176 my($md, undef) = split(/\:/, $line);
177 $md = cleanupString($md);
180 open $ch, "$_MDADM_ --detail $md -b|" or
181 die("FATAL: Unable to gather information for md device $md.\n");
188 my(undef, $uuid_t) = split(/UUID\=/, $buffer);
189 $uuid_t = cleanupString($uuid_t);
191 $MD_DEVICES{$uuid_t} = $md;
198 sub applyConfiguration {
202 my $config = readConfig($confile);
206 my $database = $$config{'DATABASE'}->{'default'}->{'NAME'};
207 my $user = $$config{'DATABASE'}->{'default'}->{'USERNAME'};
208 my $password = $$config{'DATABASE'}->{'default'}->{'PASSWORD'};
209 my $hostname = $$config{'DATABASE'}->{'default'}->{'HOST'};
211 my $db = DBI->connect("DBI:mysql:database=$database;host=$hostname", "$user", "$password");
213 my $sth = $db->prepare("SELECT device_id, device_path, options, blocksize, type_id, perf_id, md_uuid, handler_name ".
214 "FROM devices, scst_handlers ".
215 "WHERE devices.scst_handlr_id = scst_handlers.scst_handlr_id ".
216 "ORDER BY device_id");
217 die("FATAL: Unable to obtain list of devices: ".$sth->errstr."\n") if (!$sth->execute());
219 # Open new devices and assign them to handlers..
220 while (my $ref = $sth->fetchrow_hashref()) {
221 if (!$HANDLERS{$_HANDLER_MAP_{$ref->{'handler_name'}}}) {
222 print "WARNING: Handler '".$ref->{'handler_name'}."' does not exist.\n";
227 my $vname = translateDeviceName($ref->{'device_id'}, $ref->{'type_id'}, $ref->{'perf_id'});
229 next if (defined($$DEVICES{$vname}));
231 my $options = $ref->{'options'};
232 $options =~ s/\s+//; $options =~ s/\|/,/;
234 if ($ref->{'md_uuid'}) {
235 print "Using UUID for device ".$ref->{'device_id'}." ($vname).\n";
237 my $handler = $ref->{'handler_name'};
238 my $uuid = findMDDevice($ref->{'md_uuid'});
239 my $blocksize = $ref->{'blocksize'};
244 print "\t-> New device '$handler:$vname', UUID: '$uuid', ".
245 "Options: '$options' Blocksize: $blocksize.\n";
247 $errs += addDevice($handler, $vname, $uuid, $options, $blocksize);
249 } elsif ($ref->{'device_path'}) {
250 print "Using path for device ".$ref->{'device_id'}." ($vname).\n";
252 my $handler = $ref->{'handler_name'};
253 my $path = $ref->{'device_path'};
254 my $blocksize = $ref->{'blocksize'};
259 print "\t-> New device '$handler:$vname', Path: '$path', ".
260 "Options: '$options', Blocksize: $blocksize.\n";
262 $errs += addDevice($handler, $vname, $path, $options, $blocksize);
265 print "FATAL: No UUID or path configured for device ".$ref->{'device_id'}." ($vname).\n";
271 my $sth = $db->prepare("SELECT group_id, group_name FROM security_groups");
272 die("FATAL: Unable to obtain list of groups: ".$sth->errstr."\n") if (!$sth->execute());
274 # Create new groups and add users..
275 while (my $ref = $sth->fetchrow_hashref()) {
276 if (!defined($GROUPS{$ref->{'group_name'}})) {
277 my $group = $ref->{'group_name'};
282 print "\t-> New group definition '$group'.\n";
284 $errs += addGroup($group);
289 my $sth = $db->prepare("SELECT group_name, user_id ".
290 "FROM group_users, security_groups ".
291 "WHERE security_groups.group_id = group_users.group_id");
292 die("FATAL: Unable to obtain list of users: ".$sth->errstr."\n") if (!$sth->execute());
294 while (my $ref = $sth->fetchrow_hashref()) {
295 if (!defined($USERS{$ref->{'group_name'}}->{$ref->{'user_id'}})) {
296 my $group = $ref->{'group_name'};
297 my $user = $ref->{'user_id'};
302 print "\t-> New user definition '$user' for group '$group'.\n";
304 $errs += addUser($group, $user);
309 my $sth_a = $db->prepare("SELECT device_id, type_id, group_name, host_id, target_id, target_lun ".
310 "FROM assignments, security_groups ".
311 "WHERE assignments.group_id = security_groups.group_id");
312 die("FATAL: Unable to obtain list of assignments: ".$sth_a->errstr."\n") if (!$sth_a->execute());
314 # Assign new devices to groups..
315 while (my $ref_a = $sth_a->fetchrow_hashref()) {
316 if (!defined($GROUPS{$ref_a->{'group_name'}})) {
317 print "WARNING: Unable to assign to non-existant group '".$ref_a->{'group_name'}."'.\n";
322 my $sth_d = $db->prepare("SELECT type_id, perf_id FROM devices ".
323 "WHERE device_id = ".$ref_a->{'device_id'}." ".
324 "AND type_id = '".$ref_a->{'type_id'}."'");
325 die("FATAL: Unable to obtain list of device information: ".$sth_d->errstr."\n") if (!$sth_d->execute());
327 my $ref_d = $sth_d->fetchrow_hashref();
329 my $vname = translateDeviceName($ref_a->{'device_id'}, $ref_d->{'type_id'}, $ref_d->{'perf_id'});
331 my $_assignments = $ASSIGNMENTS{$ref_a->{'group_name'}};
332 next if (defined($$_assignments{$vname}));
334 my $group = $ref_a->{'group_name'};
335 my $lun = $ref_a->{'target_lun'};
340 print "\t-> New device assignment '$vname' for group '$group' at LUN $lun.\n";
342 $errs += assignDevice($group, $vname, $lun);
346 print "Encountered $errs error(s) while processing.\n" if ($errs);
351 print "Configuration checked, $changes difference(s) found with current configuation.\n";
353 print "Configuration applied.\n";
356 return $TRUE if ($errs);
368 my $_handler = $_HANDLER_MAP_{$handler};
370 if (defined($$DEVICES{$device})) {
371 print "WARNING: Device '$device' already defined.\n";
375 print "Opening virtual device '$device' at path '$path' using handler '$handler'..\n";
377 if ($SCST->openDevice($_handler, $device, $path, $options)) {
378 print "WARNING: Failed to open virtual device '$device' at path '$path' (Options: $options).\n";
382 $$DEVICES{$device} = $_handler;
390 if (defined($GROUPS{$group})) {
391 print "WARNING: Group '$group' already exists.\n";
395 print "Creating security group '$group'..\n";
397 if ($SCST->addGroup($group)) {
398 print "WARNING: Failed to create security group '$group'.\n";
411 if (!defined($GROUPS{$group})) {
412 print "WARNING: Failed to add user '$user' to group '$group', group does not exist.\n";
416 if (defined($USERS{$group}->{$user})) {
417 print "WARNING: User '$user' already exists in security group '$group'.\n";
421 print "Adding user '$user' to security group '$group'..\n";
423 if ($SCST->addUser($user, $group)) {
424 print "WARNING: Failed to add user '$user' to security group '$group'.\n";
428 $USERS{$group}->{$user}++;
439 # Put luns into something easier to parse..
440 foreach my $_group (keys %ASSIGNMENTS) {
441 my $_gAssigns = $ASSIGNMENTS{$_group};
443 foreach my $_device (keys %{$_gAssigns}) {
444 @{$allLuns{$_group}}[$$_gAssigns{$_device}] = $_device;
448 # Use the next available LUN if none specified
450 $lun = ($#{$allLuns{$group}} + 1);
451 if ($lun > $_MAX_LUNS_) {
452 print "ERROR: Unable to use next available LUN of $lun, lun out of range.\n";
456 print "Device '$device': Using next available LUN of $lun for group '$group'.\n";
459 if (($lun < 0) || ($lun > $_MAX_LUNS_)) {
460 print "ERROR: Unable to assign device '$device', lun '$lun' is out of range.\n";
464 if (!defined($$DEVICES{$device})) {
465 print "WARNING: Unable to assign non-existant device '$device' to group '$group'.\n";
469 if (@{$allLuns{$group}}[$lun]) {
470 print "ERROR: Device '$device': Lun '$lun' is already assigned to device '".@{$allLuns{$group}}[$lun]."'.\n";
474 print "Assign virtual device '$device' to group '$group' at LUN '$lun'..\n";
476 if ($SCST->assignDeviceToGroup($device, $group, $lun)) {
477 print "WARNING: Failed to assign device '$device' to group '$group'.\n";
481 if (!defined($ASSIGNMENTS{$group})) {
483 $ASSIGNMENTS{$group} = \%assignments_t;
486 my $_assignments = $ASSIGNMENTS{$group};
488 $$_assignments{$device} = $lun;
499 my $io = new IO::File $confile, O_RDONLY;
501 die("FATAL: Unable to open specified configuration file $confile: $!\n") if (!$io);
503 while (my $line = <$io>) {
504 ($line, undef) = split(/\#/, $line, 2);
505 $line = cleanupString($line);
507 if ($line =~ /^\[(.*)\]$/) {
508 ($section, $arg) = split(/\s+/, $1, 2);
509 } elsif ($section && $arg && $line) {
510 my($parameter, $value) = split(/\s+/, $line, 2);
511 $config{$section}->{$arg}->{$parameter} = $value;
523 return $MD_DEVICES{$uuid};
526 sub translateDeviceName {
527 my $device_id = shift;
531 my $device_id = sprintf("%lx", $device_id);
532 my $device_id_t = $device_id;
534 for (my $t = length($device_id); $t <= 2; $t++) {
535 $device_id_t = "0$device_id_t";
538 $device_id = $device_id_t;
540 return $type_id.$perf_id.$device_id;
554 print "\n\nBut I haven\'t finished yet!\n";