This patch adds proper updating of targets to tgt-admin.

You have to add --force/-f option to update targets which are in use.

Updating consists of two things:
- target is deleted
- target is configured, basing on its config options

Updating a target which is no longer in a config file will result in the 
target's deletion.


The patch also changes the behaviour of --execute slightly - it now tries to 
delete the targets which are not in the config file; if the target is in use, 
it won't be touched (unless --force is used); if the target is not in use, it 
will be deleted.


On my TO DO list are still:
- don't assume cid is 0 when removing targets (check for a proper cid)
- some code cleanups
- shutting down tgtd (only if there are no targets)
- adding some more options (disabling write-cache etc.)





Signed-off-by: Tomasz Chmielewski <[EMAIL PROTECTED]>

diff --git a/scripts/tgt-admin b/scripts/tgt-admin
index fe95723..354dc9c 100755
--- a/scripts/tgt-admin
+++ b/scripts/tgt-admin
@@ -30,6 +30,8 @@ This tool configures tgt targets.
                                (see "--offline help" for more info)
       --ready <value>          put all or selected targets in ready state
                                (see "--ready help" for more info)
+      --update <value>         update configuration for all or selected targets
+                               (see "--update help" for more info)
   -s, --show                   show all the targets
   -c, --conf <conf file>       specify an alternative configuration file
       --ignore-errors          continue even if tgtadm exits with non-zero code
@@ -49,6 +51,7 @@ my $execute = 0;
 my $delete = 0;
 my $offline = 0;
 my $ready = 0;
+my $update = 0;
 my $show = 0;
 my $alternate_conf="0";
 my $ignore_errors = 0;
@@ -62,6 +65,7 @@ my $result = GetOptions (
        "delete=s"      => \$delete,
        "offline=s"     => \$offline,
        "ready=s"       => \$ready,
+       "update=s"      => \$update,
        "s|show"        => \$show,
        "c|conf=s"      => \$alternate_conf,
        "ignore-errors" => \$ignore_errors,
@@ -147,7 +151,10 @@ my $option;
 my $value;
 
 sub add_targets {
-
+       my $single_target = $_[0];
+       my $configured = $_[1];
+       my $connected = $_[2];
+       my $in_configfile = $_[3];
        foreach my $k (sort keys %conf) {
 
                if ( $k eq "default-driver" ) {
@@ -166,61 +173,84 @@ sub add_targets {
                execute("# default-driver not defined, defaulting to iscsi.\n");
                $default_driver = "iscsi";
        }
-
+       
        foreach my $k (sort keys %conf) {
                if ( $k eq "target" ) {
                        foreach my $k2 (sort keys %{$conf{$k}}) {
-                               $target = $k2;
-                               my $allowall = 1;
-                               if ( not defined $tgtadm_output{$k2} ) {
-                                       # We have to find available tid
-                                       $next_tid = $next_tid + 1;
+                               # Do we run update or execute?
+                               if (length $single_target) {
+                                       if ($single_target ne $k2) {
+                                               next;
+                                       } else {
+                                               $target = $single_target;
+                                       }
+                               } else {
+                                       $target = $k2;
                                }
-                               else {
-                                       execute("# Target $target already 
exist!");
-                                       execute("# Updating Target $target");
-                                       execute("tgtadm --op update --mode 
target --tid=$next_tid -n state -v offline");
-                                       execute("tgtadm --mode target --op 
delete --tid=$next_tid");
+                               if (length $single_target) {
+                                       &main_delete($target);
                                }
+                               my $allowall = 1;
+                               if ((not defined $tgtadm_output{$k2}) || 
(length $single_target && $force == 1)) {
+                                       # We have to find available tid
+                                       if (($in_configfile == 1) && 
($configured == 0)) {
+                                               my $maxtid = &find_max_tid;
+                                               $next_tid = $maxtid + 1;
+                                       } elsif (length $single_target) {
+                                               $next_tid = 
$tgtadm_output_tid{$target};
+                                       } else {
+                                               $next_tid = $next_tid + 1;
+                                       }
+                                       # Before we add a target, we need to 
know its type
+                                       my $driver;
+                                       foreach my $k3 (sort keys 
%{$conf{$k}{$k2}}) {
+                                               $option = $k3;
+                                               $value = $conf{$k}{$k2}{$k3};
+                                               &check_value($value);
+                                               if ($option eq "driver") {
+                                                       if (ref($value) eq 
"ARRAY") {
+                                                       print "Multiple driver 
definitions not allowed!\n";
+                                                       print "Check your 
config file for errors (target: $target).\n";
+                                                       exit 1;
+                                                       }
+                                               $driver = $value;
+                                               }
+                                       }
+
+                                       if (not defined $driver) {
+                                               $driver = $default_driver;
+                                       }
 
-                               # Before we add a target, we need to know its 
type
-                               my $driver;
-                               foreach my $k3 (sort keys %{$conf{$k}{$k2}}) {
-                                       $option = $k3;
-                                       $value = $conf{$k}{$k2}{$k3};
-                                       &check($value);
-                                       if ( $option eq "driver" ) {
-                                               if (ref($value) eq "ARRAY") {
-                                               print "Multiple driver 
definitions not allowed!\n";
-                                               print "Check your config file 
for errors (target: $target).\n";
-                                               exit 1;
+                                       execute("# Adding target: $target");
+                                       execute("tgtadm --lld $driver --op new 
--mode target --tid $next_tid -T $target");
+                                       foreach my $k3 (sort keys 
%{$conf{$k}{$k2}}) {
+                                               $option = $k3;
+                                               $value = $conf{$k}{$k2}{$k3};
+                                               &check_value($value);
+                                               &process_options($driver);
+                                               # If there was no option called 
"initiator-address", it means
+                                               # we want to allow ALL 
initiators for this target
+                                               if ($option eq 
"initiator-address") {
+                                                       $allowall = 0;
                                                }
-                                       $driver = $value;
                                        }
-                               }
 
-                               if ( not defined $driver ) {
-                                       $driver = $default_driver;
-                               }
-                               execute("# Adding target: $target");
-                               execute("tgtadm --lld $driver --op new --mode 
target --tid $next_tid -T $target");
-                               foreach my $k3 (sort keys %{$conf{$k}{$k2}}) {
-                                       $option = $k3;
-                                       $value = $conf{$k}{$k2}{$k3};
-                                       &check($value);
-                                       &process_options($driver);
-                                       # If there was no option called 
"initiator-address", it means
-                                       # we want to allow ALL initiators for 
this target
-                                       if ( $option eq "initiator-address" ) {
-                                               $allowall = 0;
+                                       if ($allowall == 1) {
+                                               execute("tgtadm --lld $driver 
--op bind --mode target --tid $next_tid -I ALL");
                                        }
-                               }
 
-                               if ( $allowall == 1 ) {
-                                       execute("tgtadm --lld $driver --op bind 
--mode target --tid $next_tid -I ALL");
+                               } else {
+                                       if (not length $update) {
+                                               execute("# Target $target 
already exists!");
+                                       }
                                }
-                               execute();
                        }
+                       if (length $single_target && $in_configfile == 0 && 
$configured == 0) {
+                               print "Target $single_target is $connected 
currently not configured\n";
+                               print "and does not exist in the config file - 
can't continue!\n";
+                               exit 1;
+                       }
+                       execute();
                }
        }
 }
@@ -289,7 +319,7 @@ sub process_options {
                my @value_arr = @$value;
                foreach my $incominguser (@value_arr) {
                        my @userpass = split(/ /, $incominguser);
-                       &check($userpass[1]);
+                       &check_value($userpass[1]);
                        execute("tgtadm --lld $driver --mode account --op 
delete --user=$userpass[0]");
                        execute("tgtadm --lld $driver --mode account --op new 
--user=$userpass[0] --password=$userpass[1]");
                        execute("tgtadm --lld $driver --mode account --op bind 
--tid=$next_tid --user=$userpass[0]");
@@ -303,7 +333,7 @@ sub process_options {
                }
                execute("# Warning: only one outgoinguser is allowed. Will only 
use the first one.");
                my @userpass = split(/ /, @$value[0]);
-               &check($userpass[1]);
+               &check_value($userpass[1]);
                execute("tgtadm --lld $driver --mode account --op delete 
--user=$userpass[0]");
                execute("tgtadm --lld $driver --mode account --op new 
--user=$userpass[0] --password=$userpass[1]");
                execute("tgtadm --lld $driver --mode account --op bind 
--tid=$next_tid --user=$userpass[0] --outgoing");
@@ -340,13 +370,8 @@ sub remove_targets {
                                }
 
                                if ( $dontremove == 0 ) {
-                                       # Right now, it is not possible to 
remove a target if any initiators
-                                       # are connected to it. We'll do our 
best - offline the target first
-                                       # (so it won't accept any new 
connections), and remove.
-                                       # Note that remove will only work if no 
initiator is connected.
-                                       execute("# Removing target: 
$existing_target");
-                                       execute("tgtadm --op update --mode 
target --tid=$tgtadm_output_tid{$existing_target} -n state -v offline");
-                                       execute("tgtadm --mode target --op 
delete --tid=$tgtadm_output_tid{$existing_target}");
+                                       # Remove the target
+                                       &main_delete($existing_target);
                                }
                        }
                }
@@ -498,48 +523,60 @@ sub show_target_info {
        }
 }
 
-# Delete the targets which are not in use
-sub delete_targets {
-
-       # Check if the target is used by an initiator
-       sub check_in_use {
-               my $existing_target = $_[0];
-               my $cur_option = $_[1];
-               my $cur_tid = $_[2];
-               if ($tgtadm_output{$existing_target} =~ m/\s+Connection:/) {
-                       if ($force == 1) {
-                               # Remove ACLs first
-                               my @acl_info = 
&show_target_info($existing_target, "acl_information");
-                               foreach my $acl (@acl_info) {
-                                       execute("tgtadm --op unbind --mode 
target --tid $tgtadm_output_tid{$existing_target} -I $acl");
-                               }
-                               # Now, remove all sessions / connections from 
that tid
-                               my @sessions = 
&show_target_info($existing_target, "sessions");
-                               foreach my $session (@sessions) {
-                                       execute("tgtadm --op delete --mode conn 
--tid $tgtadm_output_tid{$existing_target} --sid $session --cid 0");
-                               }
-                               execute("tgtadm --mode target --op delete 
--tid=$tgtadm_output_tid{$existing_target}");
-                       } else {
-                               execute("# Target with tid 
$tgtadm_output_tid{$existing_target} ($existing_target) is in use, it won't be 
deleted.");
+# Main subroutine for deleting targets
+sub main_delete {
+       my $current_target = $_[0];
+       my $current_tid = $_[1];
+       my $configured = &check_configured($current_target);
+       my $del_upd_text;
+       # Check if the target has initiators connected
+       if ($tgtadm_output{$current_target} =~ m/\s+Connection:/) {
+               if ($force == 1) {
+                       execute("# Removing target: $current_target");
+                       # Remove ACLs first
+                       my @acl_info = &show_target_info($current_target, 
"acl_information");
+                       foreach my $acl (@acl_info) {
+                               execute("tgtadm --op unbind --mode target --tid 
$tgtadm_output_tid{$current_target} -I $acl");
+                       }
+                       # Now, remove all sessions / connections from that tid
+                       my @sessions = &show_target_info($current_target, 
"sessions");
+                       foreach my $session (@sessions) {
+                               execute("tgtadm --op delete --mode conn --tid 
$tgtadm_output_tid{$current_target} --sid $session --cid 0");
                        }
-               } elsif (length $tgtadm_output_tid{$existing_target}) {
-                       execute("tgtadm --mode target --op delete 
--tid=$tgtadm_output_tid{$existing_target}");
+                       execute("tgtadm --mode target --op delete 
--tid=$tgtadm_output_tid{$current_target}");
                } else {
-                       if ($cur_option eq "tid") {
-                               execute("# Target with tid $cur_tid does not 
exist!");
+                       if ($update ne 0) {
+                               $del_upd_text = "updated";
                        } else {
-                               execute("# Target $existing_target does not 
exist!");
+                               $del_upd_text = "deleted";
                        }
+                       execute("# Target with tid 
$tgtadm_output_tid{$current_target} ($current_target) is in use, it won't be 
$del_upd_text.");
+               }
+       } elsif (length $tgtadm_output_tid{$current_target}) {
+               execute("# Removing target: $current_target");
+               execute("tgtadm --mode target --op delete 
--tid=$tgtadm_output_tid{$current_target}");
+       } else {
+               if (length $current_tid) {
+                       execute("# Target with $current_target tid $current_tid 
does not exist!");
+               } else {
+                       execute("# Target with name $current_target does not 
exist!");
                }
        }
+       if ($configured ne 0) {
+               execute();
+       }
+}
 
+# Delete the targets
+sub delete_targets {
+       
        if ($delete eq "help") {
                print <<EOF;
       --delete <value>         delete all or selected targets
-                               The target will be deleted only if it's not used
+                               The target will be deleted only if it's not used
                                (no initiator is connected to it).
                                If you want to delete targets which are in use,
-                               you have to add "--force" flag
+                               you have to add "--force" flag.
 
 Example usage:
       --delete help          - display this help
@@ -551,26 +588,130 @@ EOF
                exit;
        } elsif ($delete eq "ALL") {
                &process_targets;
-               # Run over all targets and delete them if they are not in use
+               # Run over all targets and delete them
                my @all_targets = keys %tgtadm_output_tid;
-               foreach my $existing_target (@all_targets) {
-               &check_in_use($existing_target);
+               foreach my $current_target (@all_targets) {
+                       &main_delete($current_target);
                }
-       } elsif ($delete =~ m/tid=(.+)/) {
+       } elsif ($delete =~ m/^tid=(.+)/) {
                # Delete by tid
                &process_targets;
-               my $existing_target = $1;
-               &check_in_use($tgtadm_output_name{$existing_target}, "tid", 
$existing_target);
+               my $current_target = $tgtadm_output_name{$1};
+               &main_delete($current_target, $1);
        } else {
                # Delete by name
                &process_targets;
-               my $existing_target = $delete;
-               &check_in_use($existing_target);
+               my $current_target = $delete;
+               &main_delete($current_target);
+       }
+}
+
+# Update targets
+sub update_targets {
+       if ($update eq "help") {
+               print <<EOF;
+      --update <value>         update all or selected targets
+                               The target will be update only if it's not used
+                               (no initiator is connected to it).
+                               If you want to update targets which are in use,
+                               you have to add "--force" flag.
+
+Example usage:
+      --update help          - display this help
+      --update ALL           - update all targets
+      --update tid=4         - update target 4 (target with tid 4)
+      --update iqn.2008-08.com.example:some.target - update this target
+
+EOF
+               exit;
+       } elsif ($update eq "ALL") {
+               # Run over all targets and delete them if they are not in use
+               &parse_configs;
+               &process_targets;
+#              my @all_targets = keys %tgtadm_output_tid;
+               my @targets_combined = &combine_targets;
+               foreach my $current_target (@targets_combined) {
+                       my $configured = &check_configured($current_target);
+                       my $connected = &check_connected($current_target);
+                       my $in_configfile = 
&check_in_configfile($current_target);
+                       &combine_targets;
+                       if (($in_configfile == 0) && ($configured == 1)) {
+                               # Delete the target if it's not in the config 
file
+                               &main_delete($current_target);
+                       } else {
+                               &add_targets($current_target, $configured, 
$connected, $in_configfile);
+                       }
+
+               }
+       } elsif ($update =~ m/^tid=(.+)/) {
+               # Update by tid
+               &parse_configs;
+               &process_targets;
+               my $current_target = $tgtadm_output_name{$1};
+               my $configured = &check_configured($current_target);
+               my $connected = &check_connected($current_target);
+               my $in_configfile = &check_in_configfile($current_target);
+               if (($in_configfile == 0) && ($configured == 1)) {
+                       # Delete the target if it's not in the config file
+                       &main_delete($current_target);
+               } elsif ($configured == 1) {
+                       &add_targets($current_target, $configured, $connected);
+               } else {
+                       print "There is no target with tid $1, can't 
continue!\n";
+                       exit 1;
+               }
+       } else {
+               # Update by name
+               &parse_configs;
+               &process_targets;
+               my $current_target = $update;
+               my $configured = &check_configured($current_target);
+               my $connected = &check_connected($current_target);
+               my $in_configfile = &check_in_configfile($current_target);
+               if (($in_configfile == 0) && ($configured == 1)) {
+                       # Delete the target if it's not in the config file
+                       &main_delete($current_target);
+               } else {
+                       &add_targets($current_target, $configured, $connected);
+               }
+       }
+}
+
+# Find the biggest tid
+sub find_max_tid {
+       my @all_targets = keys %tgtadm_output_tid;
+       my $maxtid = 0;
+       foreach my $var (@all_targets) {
+               if ($tgtadm_output_tid{$var} > $maxtid) {
+                       $maxtid = $tgtadm_output_tid{$var};
+               }
+               return $maxtid;
+       }
+}
+
+# Combine targets from the config file and currently configured targets
+sub combine_targets {
+       my @targets_in_configfile;
+       my @all_targets = keys %tgtadm_output_tid;
+       my @targets_combined;
+       # Make an array of targets in the config file
+       foreach my $k (sort keys %conf) {
+               if ( $k eq "target" ) {
+                       foreach my $k2 (sort keys %{$conf{$k}}) {
+                               push(@targets_in_configfile, $k2)
+                       }
+               }
+       }
+       # Use only unique elements from bot arrays
+       foreach my $target (@all_targets) {
+               push (@targets_combined, $target) unless grep { $_ eq $target } 
@targets_in_configfile;
        }
+       @targets_combined = (@targets_combined, @targets_in_configfile);
+       return @targets_combined;
 }
 
-# Some checks
-sub check {
+# Check if a value is correct
+sub check_value {
        if ( not defined $_[0] or not length $_[0] ) {
                print "\nOption $option has a missing value!\n";
                print "Check your config file for errors (target: $target)\n";
@@ -578,6 +719,42 @@ sub check {
        }
 }
 
+# Check if the target is in the config file
+sub check_in_configfile {
+       my $current_target = $_[0];
+       my $result;
+       foreach my $k (sort keys %conf) {
+               if ( $k eq "target" ) {
+                       foreach my $k2 (sort keys %{$conf{$k}}) {
+                               if ($k2 eq $current_target) {
+                                       return 1;
+                               }
+                       }
+                       # If we're here, we didn't find a match
+                       return 0;
+               }
+       }
+}
+
+# Check if the target is configured in tgtd
+sub check_configured {
+       my $current_target = $_[0];
+       if (length $tgtadm_output_tid{$current_target}) {
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+# Check if any initiators are connected to the target
+sub check_connected {
+       my $current_target = $_[0];
+       if ($tgtadm_output{$current_target} =~ m/\s+Connection:/) {
+               return 1;
+       } else {
+               return 0;
+       }
+}
 
 # Execute or just print (or both) everything we start or would start
 sub execute {
@@ -612,6 +789,8 @@ if ($execute == 1) {
        &remove_targets;
 } elsif ($delete ne 0) {
        &delete_targets;
+} elsif ($update ne 0) {
+       &update_targets;
 } elsif ($dump == 1) {
        &dump_config;
 } elsif ($offline ne 0) {



-- 
Tomasz Chmielewski
http://wpkg.org
_______________________________________________
Stgt-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/stgt-devel

Reply via email to