lsslp second phase code drop(without man page)
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@2625 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
		| @@ -154,7 +154,14 @@ sub refresh_table { | ||||
|   $self->{switches} = {}; | ||||
|   foreach $entry (@entries) { | ||||
|     if (defined($entry->{switch}) and $entry->{switch} ne "" and defined($entry->{port}) and $entry->{port} ne "") { | ||||
|     	$self->{switches}->{$entry->{switch}}->{$entry->{port}}=$entry->{node}; | ||||
|     	if ( !$self->{switches}->{$entry->{switch}}->{$entry->{port}}) | ||||
|         { | ||||
|             $self->{switches}->{$entry->{switch}}->{$entry->{port}} = $entry->{node}; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             $self->{switches}->{$entry->{switch}}->{$entry->{port}} .= ",$entry->{node}"; | ||||
|         } | ||||
|     } else { | ||||
|         xCAT::MsgUtils->message("S","xCAT Table error:".$entry->{node}."Has missing or invalid switch.switch and/or switch.port fields"); | ||||
|     } | ||||
|   | ||||
| @@ -335,7 +335,7 @@ sub resolve_hcp { | ||||
|     my $request   = shift; | ||||
|     my $noderange = shift; | ||||
|     my @nodegroup = (); | ||||
|     my $tab       = ($request->{hwtype} eq "fsp") ? "ppcdirect" : "ppchcp"; | ||||
|     my $tab       = ($request->{hwtype} eq "fsp" or $request->{hwtype} eq "bpa") ? "ppcdirect" : "ppchcp"; | ||||
|     my $db        = xCAT::Table->new( $tab ); | ||||
|  | ||||
|     #################################### | ||||
| @@ -391,7 +391,7 @@ sub preprocess_nodes { | ||||
|     #   Direct-attached FSP  | ||||
|     ######################################## | ||||
|     if (( $request->{command} =~ /^(rscan|rspconfig)$/ ) or | ||||
|         ( $request->{hwtype} eq "fsp" )) { | ||||
|         ( $request->{hwtype} eq "fsp" or $request->{hwtype} eq "bpa")) { | ||||
|         my $result = resolve_hcp( $request, $noderange ); | ||||
|         return( $result ); | ||||
|     } | ||||
| @@ -817,7 +817,7 @@ sub invoke_cmd { | ||||
|     ######################################## | ||||
|     # Direct-attached FSP handler  | ||||
|     ######################################## | ||||
|     if ( $hwtype eq "fsp" ) { | ||||
|     if ( $hwtype eq "fsp" or $hwtype eq "bpa") { | ||||
|    | ||||
|         #################################### | ||||
|         # Dynamically load FSP module | ||||
| @@ -1013,7 +1013,7 @@ sub preprocess_request { | ||||
|   # get the HCPs for the LPARs in order to figure out which service  | ||||
|   # nodes to send the requests to | ||||
|   ################################################################### | ||||
|   my $hcptab_name = ($package eq "fsp") ? "ppcdirect" : "ppchcp"; | ||||
|   my $hcptab_name = ($package eq "fsp" or $package eq "bpa") ? "ppcdirect" : "ppchcp"; | ||||
|   my $hcptab  = xCAT::Table->new( $hcptab_name ); | ||||
|   unless ($hcptab ) { | ||||
|     $callback->({data=>["Cannot open $hcptab_name table"]}); | ||||
| @@ -1298,5 +1298,76 @@ sub sshcmds_on_hmc | ||||
|     return ([0, undef, \@data]); | ||||
| } | ||||
|  | ||||
| ########################################################################## | ||||
| # logon asm and update configuration | ||||
| ########################################################################## | ||||
| sub updconf_in_asm | ||||
| { | ||||
|     my $ip = shift; | ||||
|     my $target_dev = shift; | ||||
|     my @cmds = @_; | ||||
|  | ||||
|     eval { require xCAT::PPCfsp }; | ||||
|     if ( $@ ) { | ||||
|         return ([1,@cmds]); | ||||
|     } | ||||
|  | ||||
|     my %handled; | ||||
|     for my $cmd (@cmds) | ||||
|     { | ||||
|         if ( $cmd =~ /(.+?)=(.*)/) | ||||
|         { | ||||
|             my ($command,$value) = ($1,$2); | ||||
|             $handled{$command} = $value; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     my %request = ( | ||||
|             ppcretry    => 1, | ||||
|             verbose     => 0, | ||||
|             ppcmaxp     => 64, | ||||
|             ppctimeout  => 0, | ||||
|             fsptimeout  => 0, | ||||
|             ppcretry    => 3, | ||||
|             maxssh      => 10, | ||||
|             arg         => \@cmds, | ||||
|             method      => \%handled, | ||||
|             command     => 'rspconfig', | ||||
|             hwtype      => lc($target_dev->{'type'}), | ||||
|             ); | ||||
|  | ||||
|     my $valid_ip; | ||||
|     my @exp; | ||||
|     foreach my $individual_ip ( split /,/, $ip ) { | ||||
|          ################################ | ||||
|          # Get userid and password  | ||||
|          ################################ | ||||
|          my @cred = xCAT::PPCdb::credentials( $individual_ip, lc($target_dev->{'type'})); | ||||
|         $request{$individual_ip}{cred} = \@cred; | ||||
|         $request{node} = [$individual_ip];   | ||||
|  | ||||
|         @exp = xCAT::PPCfsp::connect(\%request, $individual_ip); | ||||
| #################################### | ||||
| # Successfully connected  | ||||
| #################################### | ||||
|         if ( ref($exp[0]) eq "LWP::UserAgent" ) { | ||||
|             $valid_ip = $individual_ip; | ||||
|             last; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| #################################### | ||||
| # Error connecting  | ||||
| #################################### | ||||
|     if ( ref($exp[0]) ne "LWP::UserAgent" ) { | ||||
|         return ([1,@cmds]); | ||||
|     } | ||||
|     my $result = xCAT::PPCfsp::handler( $valid_ip, \%request, \@exp ); | ||||
|     my $RC = shift( @$result); | ||||
|     my @data; | ||||
|     push @data, @$result[0]; | ||||
|  | ||||
|     return ([0, undef, \@data]); | ||||
| } | ||||
| 1; | ||||
|  | ||||
|   | ||||
| @@ -35,13 +35,18 @@ sub parse_args { | ||||
|         "date", | ||||
|         "autopower", | ||||
|         "sysdump", | ||||
|         "spdump" | ||||
|         "spdump", | ||||
|         "network" | ||||
|     ); | ||||
|     my @bpa = ( | ||||
|         "network" | ||||
|     ); | ||||
|     my @ppc = ( | ||||
|         "sshcfg" | ||||
|     ); | ||||
|     my %rsp = ( | ||||
|         fsp => \@fsp, | ||||
|         bpa => \@bpa, | ||||
|         ivm => \@ppc, | ||||
|         hmc => \@ppc | ||||
|     ); | ||||
| @@ -183,6 +188,16 @@ sub parse_option { | ||||
|            return( "Invalid argument '$value'" ); | ||||
|        } | ||||
|     } | ||||
|     if ( $command eq 'network'){ | ||||
|         my ( $adapter_name, $ip, $host, $gateway, $netmask) = | ||||
|                 split /,/, $value; | ||||
|         return ( "Network interface name is required") if ( ! $adapter_name); | ||||
|         return ( "Invalide network interface name $adapter_name") if ( $adapter_name !~ /^eth\d$/); | ||||
|         return undef if ( $ip eq '*'); | ||||
|         return ( "Invalid IP address format") if ( $ip and $ip !~ /\d+\.\d+\.\d+\.\d+/); | ||||
|         return ( "Invalid netmask format") if ( $netmask and $netmask !~ /\d+\.\d+\.\d+\.\d+/); | ||||
|     } | ||||
|  | ||||
|     return undef; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,8 @@ use xCAT::GlobalDef; | ||||
| my %logon = ( | ||||
|     hmc => ["hscroot","abc123"], | ||||
|     ivm => ["padmin", "padmin"], | ||||
|     fsp => ["admin",  "admin"] | ||||
|     fsp => ["admin",  "admin"], | ||||
|     bpa => ["admin",  "admin"] | ||||
| ); | ||||
|  | ||||
| ########################################### | ||||
| @@ -21,9 +22,19 @@ my %logon = ( | ||||
| my %hcptab = ( | ||||
|     hmc => "ppchcp", | ||||
|     ivm => "ppchcp", | ||||
|     fsp => "ppcdirect" | ||||
|     fsp => "ppcdirect", | ||||
|     bpa => "ppcdirect" | ||||
| ); | ||||
|  | ||||
| ########################################### | ||||
| # The default groups of hcp | ||||
| ########################################### | ||||
| my %defaultgrp = ( | ||||
|     hmc => "hmc", | ||||
|     ivm => "ivm", | ||||
|     fsp => "fsp", | ||||
|     bpa => "bpa" | ||||
| ); | ||||
|  | ||||
|  | ||||
| ########################################################################## | ||||
| @@ -301,7 +312,15 @@ sub credentials { | ||||
|     $tab = xCAT::Table->new( $hcptab{$hwtype} ); | ||||
|     if ( $tab ) { | ||||
|         my ($ent) = $tab->getAttribs( {hcp=>$server}, qw(username password)); | ||||
|         if ( $ent ) { | ||||
|         if ( $ent){ | ||||
|             if (defined($ent->{password})) { $pass = $ent->{password}; } | ||||
|             if (defined($ent->{username})) { $user = $ent->{username}; } | ||||
|         } | ||||
|     ############################################################## | ||||
|     # If no user/passwd found, check if there is a default group | ||||
|     ############################################################## | ||||
|         elsif( ($ent) = $tab->getAttribs( {hcp=>$defaultgrp{$hwtype}}, qw(username password))) | ||||
|         { | ||||
|             if (defined($ent->{password})) { $pass = $ent->{password}; } | ||||
|             if (defined($ent->{username})) { $user = $ent->{username}; } | ||||
|         } | ||||
| @@ -312,10 +331,3 @@ sub credentials { | ||||
|  | ||||
| 1; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -33,7 +33,8 @@ my %cmds = ( | ||||
|      date          => ["Time Of Day",                   \&date],  | ||||
|      autopower     => ["Auto Power Restart",            \&autopower], | ||||
|      sysdump       => ["System Dump",                   \&sysdump], | ||||
|      spdump        => ["Service Processor Dump",        \&spdump] }, | ||||
|      spdump        => ["Service Processor Dump",        \&spdump], | ||||
|      network       => ["Network Configuration",         \&netcfg]}, | ||||
| ); | ||||
|  | ||||
|  | ||||
| @@ -1554,11 +1555,273 @@ sub all_clear { | ||||
|     return( $result ); | ||||
| } | ||||
|  | ||||
| ########################################################################## | ||||
| # Gets and set network configuration | ||||
| ########################################################################## | ||||
| sub netcfg | ||||
| { | ||||
|     my $exp     = shift; | ||||
|     my $request = shift; | ||||
|     my $id      = shift; | ||||
|      | ||||
|     ###################################### | ||||
|     # Parsing arg | ||||
|     ###################################### | ||||
|     my $set_config = 0; | ||||
|     my ($inc_name, $inc_ip, $inc_host, $inc_gateway, $inc_netmask) = (); | ||||
|     my $real_inc_name = undef; | ||||
|     if ( $request->{'method'}->{'network'}) | ||||
|     { | ||||
|         $set_config = 1; | ||||
|     } | ||||
|      | ||||
|     my $interfaces = undef; | ||||
|     my $form = undef; | ||||
|      | ||||
|     my $res = get_netcfg( $exp, $request, $id, \$interfaces, \$form); | ||||
|  | ||||
|     return $res if ( $res->[0] == RC_ERROR); | ||||
| 		 | ||||
|     my $output = ""; | ||||
|     ####################################### | ||||
|     # Set configuration | ||||
|     ####################################### | ||||
|     if ( $set_config) | ||||
|     { | ||||
|         return set_netcfg( $exp, $request, $interfaces, $form); | ||||
|     } | ||||
|     ####################################### | ||||
|     # Get configuration and format output | ||||
|     ####################################### | ||||
|     else | ||||
|     { | ||||
|         return format_netcfg( $interfaces); | ||||
|     } | ||||
|      | ||||
| } | ||||
|  | ||||
| ########################################################################## | ||||
| # Gets network configuration | ||||
| ########################################################################## | ||||
| sub get_netcfg | ||||
| { | ||||
|     my $exp        = shift; | ||||
|     my $request    = shift; | ||||
|     my $id         = shift; | ||||
|     my $interfaces = shift; | ||||
|     my $form       = shift; | ||||
|     my $ua         = @$exp[0]; | ||||
|     my $server     = @$exp[1]; | ||||
| 	###################################### | ||||
|     # Get Network Configuration URL | ||||
|     ###################################### | ||||
|     my $url = "https://$server/cgi-bin/cgi?form=$id"; | ||||
|     my $res = $ua->get( $url ); | ||||
|     | ||||
|     ################################## | ||||
|     # Return error | ||||
|     ################################## | ||||
|     if ( !$res->is_success() ) { | ||||
|         return( [RC_ERROR,$res->status_line] ); | ||||
|     } | ||||
|  | ||||
|     ################################## | ||||
|     # Get "Network Configuraiton" form  | ||||
|     ################################## | ||||
|     $$form = HTML::Form->parse( $res->content, $res->base ); | ||||
|  | ||||
|     ################################## | ||||
|     # Return error | ||||
|     ################################## | ||||
|     if ( !defined( $$form )) { | ||||
|         return( [RC_ERROR,"'Network Configuration' form not found"] ); | ||||
|     }  | ||||
|  | ||||
|     ################################## | ||||
|     # For some P6 machines | ||||
|     ################################## | ||||
|     if ( $$form->find_input('ip', 'radio', 1)) | ||||
|     {     | ||||
|         my $ipv4Radio = $$form->find_input('ip', 'radio', 1); | ||||
|         if (!$ipv4Radio) | ||||
|         { | ||||
|             print "Cannot find IPv4 option\n"; | ||||
|             exit; | ||||
|         } | ||||
|         #$ipv4Radio->check(); | ||||
|  | ||||
|         my $data = $$form->click('submit'); | ||||
|         $res = $ua->request( $data); | ||||
|         $$form = HTML::Form->parse( $res->content, $res->base ); | ||||
|         if ( !defined( $$form )) { | ||||
|             return( [RC_ERROR,"'Network Configuration' form not found"] ); | ||||
|         }  | ||||
|     } | ||||
|      | ||||
|     ####################################### | ||||
|     # Parse the form to get the inc input | ||||
|     ####################################### | ||||
|     my $has_found_all = 0; | ||||
|     my $i = 0; | ||||
|     while ( not $has_found_all) | ||||
|     { | ||||
|         my $input = $$form->find_input( "interface$i", 'checkbox'); | ||||
|         if ( ! $input) | ||||
|         { | ||||
|             $has_found_all = 1; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             $$interfaces->{"interface$i"}->{'selected'} = $input; | ||||
|             $$interfaces->{"interface$i"}->{'type'}     = $$form->find_input("ip$i", 'option'); | ||||
|             $$interfaces->{"interface$i"}->{'hostname'} = $$form->find_input("host$i", 'text'); | ||||
|             $$interfaces->{"interface$i"}->{'ip'}       = $$form->find_input("static_ip$i", 'text'); | ||||
|             $$interfaces->{"interface$i"}->{'gateway'}  = $$form->find_input("gateway$i", 'text'); | ||||
|             $$interfaces->{"interface$i"}->{'netmask'}  = $$form->find_input("subnet$i", 'text'); | ||||
|             #we do not support dns yet, just in case of future support | ||||
|             $$interfaces->{"interface$i"}->{'dns0'}     = $$form->find_input("dns0$i", 'text'); | ||||
|             $$interfaces->{"interface$i"}->{'dns1'}     = $$form->find_input("dns1$i", 'text'); | ||||
|             $$interfaces->{"interface$i"}->{'dns2'}     = $$form->find_input("dns2$i", 'text'); | ||||
|             $i++; | ||||
|         } | ||||
|     } | ||||
|     return ( [RC_ERROR,"Cannot find any network interface on $server"]) if ( ! $$interfaces); | ||||
|      | ||||
|     return ( [SUCCESS, undef]); | ||||
| } | ||||
|  | ||||
| ########################################################################## | ||||
| # Set network configuration | ||||
| ########################################################################## | ||||
| sub set_netcfg | ||||
| { | ||||
|     my $exp         = shift; | ||||
|     my $request     = shift; | ||||
|     my $interfaces  = shift; | ||||
|     my $form        = shift; | ||||
|     my $ua          = @$exp[0]; | ||||
|  | ||||
|     my $real_inc_name; | ||||
|     my ($inc_name, $inc_ip, $inc_host, $inc_gateway, $inc_netmask) = split /,/, $request->{'method'}->{'network'}; | ||||
|  | ||||
|     chomp ($inc_name, $inc_ip, $inc_host, $inc_gateway, $inc_netmask); | ||||
|     if ( $inc_name =~ /^eth(\d)$/) | ||||
|     { | ||||
|         $real_inc_name = "interface$1"; | ||||
|     } | ||||
|     elsif ( $inc_name =~/(\d+)\.(\d+)\.(\d+)\.(\d+)/) | ||||
|     { | ||||
|         for my $inc (keys %$interfaces) | ||||
|         { | ||||
|             if ($interfaces->{ $inc}->{'ip'}->value() eq $inc_name) | ||||
|             { | ||||
|                 $real_inc_name = $inc; | ||||
|                 last; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return( [RC_ERROR, "Incorrect network interface name $inc_name"] ); | ||||
|     } | ||||
|  | ||||
|     return ( [RC_ERROR,"Cannot find interface $inc_name"]) if ( ! exists ($$interfaces{ $real_inc_name})); | ||||
|  | ||||
|     $interfaces->{ $real_inc_name}->{'selected'}->check(); | ||||
|  | ||||
|     if ( $interfaces->{ $real_inc_name}->{'type'}) | ||||
|     { | ||||
|         $interfaces->{ $real_inc_name}->{'type'}->value('Static'); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return ( [RC_ERROR,"Cannot set this interface to static type"]); | ||||
|     } | ||||
|     my @set_entries = (); | ||||
|     if ( $inc_ip ) | ||||
|     { | ||||
|         return ( [RC_ERROR,"Cannot set IP address to $inc_ip"]) if (! $interfaces->{ $real_inc_name}->{'ip'}); | ||||
|         $interfaces->{ $real_inc_name}->{'ip'}->value( $inc_ip); | ||||
|         push @set_entries, 'IP address'; | ||||
|     } | ||||
|     if ( $inc_host) | ||||
|     { | ||||
|         return ( [RC_ERROR,"Cannot set hostname to $inc_host"]) if (! $interfaces->{ $real_inc_name}->{'hostname'}); | ||||
|         $interfaces->{ $real_inc_name}->{'hostname'}->value( $inc_host); | ||||
|         push @set_entries, 'hostname'; | ||||
|     } | ||||
|     if ( $inc_gateway) | ||||
|     { | ||||
|         return ( [RC_ERROR,"Cannot set gateway to $inc_gateway"]) if (! $interfaces->{ $real_inc_name}->{'gateway'}); | ||||
|         $interfaces->{ $real_inc_name}->{'gateway'}->value( $inc_gateway); | ||||
|         push @set_entries, 'gateway'; | ||||
|     } | ||||
|     if ( $inc_netmask) | ||||
|     { | ||||
|         return ( [RC_ERROR,"Cannot set netmask to $inc_netmask"]) if (! $interfaces->{ $real_inc_name}->{'netmask'}); | ||||
|         $interfaces->{ $real_inc_name}->{'netmask'}->value( $inc_netmask); | ||||
|         push @set_entries, 'netmask'; | ||||
|     } | ||||
|  | ||||
|     #Click "Continue" button | ||||
|     my $data = $form->click('save'); | ||||
|     my $res = $ua->request( $data); | ||||
|     if (!$res->is_success()) | ||||
|     { | ||||
|         return ( [RC_ERROR, "Failed to set " . join ',', @set_entries]); | ||||
|     } | ||||
|  | ||||
|     #Go to the confirm page | ||||
|     $form = HTML::Form->parse( $res->content, $res->base ); | ||||
| #    $data = $form->click('submit'); | ||||
|     $res = $ua->request( $data); | ||||
|     if ($res->is_success()) | ||||
|     { | ||||
|         return ( [SUCCESS, "Success to set " . join ',', @set_entries]); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return ( [RC_ERROR, "Failed to set " . join ',', @set_entries]); | ||||
|     } | ||||
| } | ||||
|  | ||||
| ########################################################################## | ||||
| # Format the output of network configuration | ||||
| ########################################################################## | ||||
| sub format_netcfg | ||||
| { | ||||
|     my $interfaces  = shift; | ||||
|     my $output      = undef; | ||||
|     for my $inc ( sort keys %$interfaces) | ||||
|     { | ||||
| #improve needed: need to make the output consistent to MM             | ||||
|         $output .= "\n\t" . $inc . ":\n"; | ||||
|         $output =~ s/interface(\d)/eth$1/; | ||||
|         # There are 2 possible value for $type,  | ||||
|         # 1 means "Dynamic", 2 means "Static" | ||||
|         # Now to find the correct type name | ||||
|         my @possible_values = $interfaces->{$inc}->{'type'}->possible_values(); | ||||
|         my @possible_names  = $interfaces->{$inc}->{'type'}->value_names(); | ||||
|         my %value_names = {}; | ||||
|         for ( my $i = 0; $i < scalar( @possible_values); $i++) | ||||
|         { | ||||
|             $value_names{ @possible_values[$i]} = @possible_names[$i]; | ||||
|         } | ||||
|         my $type = $interfaces->{$inc}->{'type'} ? $value_names{ $interfaces->{$inc}->{'type'}->value()} : undef;; | ||||
|         $type = "Static" if ( $type == 2); | ||||
|         my $ip = $interfaces->{$inc}->{'ip'} ? $interfaces->{$inc}->{'ip'}->value() : undef; | ||||
|         my $hostname = $interfaces->{$inc}->{'hostname'} ? $interfaces->{$inc}->{'hostname'}->value() : undef; | ||||
|         my $gateway = $interfaces->{$inc}->{'gateway'} ? $interfaces->{$inc}->{'gateway'}->value() : undef; | ||||
|         my $netmask = $interfaces->{$inc}->{'netmask'} ? $interfaces->{$inc}->{'netmask'}->value() : undef; | ||||
|  | ||||
|         $output .= "\t\tIP Type: "    . $type     . "\n"; | ||||
|         $output .= "\t\tIP Address: " . $ip       . "\n"; | ||||
|         $output .= "\t\tHostname: "   . $hostname . "\n"; | ||||
|         $output .= "\t\tGateway: "    . $gateway  . "\n"; | ||||
|         $output .= "\t\tNetmask: "    . $netmask  . "\n"; | ||||
|     } | ||||
|     return( [SUCCESS,$output] ); | ||||
| } | ||||
|  | ||||
| 1; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -116,7 +116,7 @@ my %usage = ( | ||||
|        rmvm [-h|--help|-v|--version]", | ||||
|     "lsslp" => | ||||
| "Usage: lsslp [-h|--help|-v|--version] | ||||
|        lsslp [-V|--verbose][-i ip[,ip..]][-w][-r|-x|-z][-s BPA|MM|IVM|RSA|FSP|HMC] | ||||
|        lsslp [-V|--verbose][-i ip[,ip..]][-w][-u] [-r|-x|-z][-s BPA|MM|IVM|RSA|FSP|HMC] | ||||
|              [-t tries][-m][-e cmd][-c [timeout[timeout,..]]]", | ||||
|   "rflash" => | ||||
| "Usage: rflash [ -h|--help|-v|--version] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user