Added os install utilities to sol_utils.tcl

Change-Id: I471fa4ce15853a32b6d0d9c3bc548564a2791bf2
Signed-off-by: Joy Onyerikwu <onyekachukwu.joy.onyerikwu@ibm.com>
diff --git a/bin/sol_utils.tcl b/bin/sol_utils.tcl
index e5be1b6..aa8f831 100755
--- a/bin/sol_utils.tcl
+++ b/bin/sol_utils.tcl
@@ -10,14 +10,16 @@
 # --proc_name=boot_to_petitboot
 
 source [exec bash -c "which source.tcl"]
-my_source [list print.tcl opt.tcl valid.tcl call_stack.tcl tools.exp]
+my_source \
+[list print.tcl opt.tcl valid.tcl call_stack.tcl tools.exp cmd.tcl host.tcl]
 
 longoptions openbmc_host: openbmc_username:=root openbmc_password:=0penBmc\
-  os_host: os_username:=root os_password: proc_name:=boot_to_petitboot\
-  test_mode:=0 quiet:=0 debug:=0
+  os_host: os_username:=root os_password: proc_name: ftp_username: \
+  ftp_password: os_repo_url: test_mode:=0 quiet:=0 debug:=0
 pos_parms
 
-set valid_proc_name [list os_login boot_to_petitboot]
+set valid_proc_name [list os_login boot_to_petitboot go_to_petitboot_shell \
+  install_os time_settings software_selection root_password]
 
 # Create help dictionary for call to gen_print_help.
 set help_dict [dict create\
@@ -41,6 +43,7 @@
   os_login_prompt 0\
   os_logged_in 0\
   petitboot_screen 0\
+  petitboot_shell_prompt 0\
 ]
 
 
@@ -83,9 +86,15 @@
   valid_value openbmc_password
   valid_value os_host
   valid_value os_username
-  valid_value os_password
+  valid_password os_password
   global valid_proc_name
-  valid_value proc_name {} $valid_proc_name
+  global proc_name proc_names
+  set proc_names [split $proc_name " "]
+  if { $proc_name == "install_os"} {
+    valid_value ftp_username
+    valid_password ftp_password
+    valid_value os_repo_url
+  }
 
 }
 
@@ -199,6 +208,8 @@
   global os_login_prompt_regex
   global os_prompt_regex
   global petitboot_screen_regex
+  global petitboot_shell_prompt_regex
+  global installer_screen_regex
 
   if { ! [dict get $state ssh_logged_in] } {
     puts stderr ""
@@ -212,8 +223,9 @@
   # see where things stand.
   send_wrap ""
   set expect_result [expect_wrap\
-    [list $os_login_prompt_regex $os_prompt_regex $petitboot_screen_regex]\
-    "any indication of status" 5]
+  [list $os_login_prompt_regex $os_prompt_regex $petitboot_screen_regex \
+  $petitboot_shell_prompt_regex $installer_screen_regex] \
+  "any indication of status" 5 0]
 
   switch $expect_result {
     0 {
@@ -225,6 +237,9 @@
     2 {
       dict set state petitboot_screen 1
     }
+    3 {
+      dict set state petitboot_shell_prompt 1
+    }
   }
 
   dprintn ; dprint_dict state
@@ -234,7 +249,7 @@
 
 proc os_login {} {
 
-  # Login to the OS
+  # Login to the OS.
 
   dprintn ; dprint_executing
 
@@ -411,7 +426,17 @@
   global petitboot_screen_regex
 
   if { [dict get $state petitboot_screen] } {
-    qprintn ; qprint_timen "We are already at petiboot."
+    qprintn ; qprint_timen "Already at petiboot."
+    return
+  }
+
+  if { [dict get $state petitboot_shell_prompt] } {
+    qprintn ; qprint_timen "Now at the shell prompt. Going to petitboot."
+    send_wrap "exit"
+    set expect_result [expect_wrap [list $petitboot_screen_regex]\
+    "the petitboot screen" 900]
+    dict set state petitboot_shell_prompt 0
+    dict set state petitboot_screen 1
     return
   }
 
@@ -447,6 +472,301 @@
 }
 
 
+proc go_to_petitboot_shell {} {
+
+  # Go to petitboot shell.
+  global spawn_id
+  global state
+  global expect_out
+  global petitboot_shell_prompt_regex
+
+  if { [dict get $state petitboot_shell_prompt] } {
+    qprintn ; qprint_timen "Already at the shell prompt."
+    return
+  }
+
+  eval boot_to_petitboot
+  send_wrap "x"
+  set expect_result [expect_wrap [list $petitboot_shell_prompt_regex]\
+    "the shell prompt" 10]
+  dict set state petitboot_screen 0
+  dict set state petitboot_shell_prompt 1
+  qprintn ; qprint_timen "Arrived at the shell prompt."
+  qprintn ; qprint_timen state
+
+}
+
+
+proc installation_destination {} {
+
+  # Set the software installation destination.
+
+  # Expectation is that we are starting at the "Installation" options screen.
+
+  dprintn ; dprint_executing
+
+  global spawn_id
+  global expect_out
+  global state
+  global installer_screen_regex
+
+  qprintn ; qprint_timen "Presumed to be at \"Installation\" screen."
+
+  qprintn ; qprint_timen "Setting Installation Destination."
+  # Option 5). Installation Destination
+  qprintn ; qprint_timen "Selecting \"Installation Destination\" option."
+  send_wrap "5"
+  expect_wrap [list "Installation Destination"] "installation destination\
+  menu" 30
+
+  qprintn ; qprint_timen "Selecting \"Select all\" option."
+  send_wrap "3"
+  expect_wrap [list "Select all"] "selected all disks" 10
+
+  qprintn ; qprint_timen "Selecting \"continue\" option."
+  send_wrap "c"
+  expect_wrap [list "Autopartitioning"] "autopartitioning options" 10
+
+  qprintn ; qprint_timen "\
+  Selecting \"Replace Existing Linux system(s)\" option."
+  send_wrap "1"
+  expect_wrap [list "Replace"] "selected stanard partition" 10
+
+  qprintn ; qprint_timen "Selecting \"continue\" option."
+  send_wrap "c"
+  expect_wrap [list "Partition Scheme"] "partition scheme options" 10
+
+  qprintn ; qprint_timen "Selecting \"LVM\" option."
+  send_wrap "3"
+  expect_wrap [list "LVM"] "lvm option" 10
+
+  qprintn ; qprint_timen "Selecting \"continue\" option."
+  send_wrap "c"
+  expect_wrap [list $installer_screen_regex] "installation options screen" 10
+
+}
+
+
+proc time_settings {} {
+
+  # Set the time/zone via the petitboot shell prompt "Time settings" menu.
+
+  # Expectation is that we are starting at the "Installation" options screen.
+
+  dprintn ; dprint_executing
+
+  global spawn_id
+  global expect_out
+  global state
+  global installer_screen_regex
+
+  # Option 2). Timezone.
+
+  qprintn ; qprint_timen "Presumed to be at \"Installation\" screen."
+  qprintn ; qprint_timen "Setting time."
+
+  qprintn ; qprint_timen "Selecting \"Time settings\"."
+  send_wrap "2"
+  expect_wrap [list "Set timezone" "Time settings"] "Time settings menu" 30
+
+  qprintn ; qprint_timen "Selecting \"Change timezone\"."
+  send_wrap "1"
+  expect_wrap [list "Available regions"] "available regions menu" 10
+
+  qprintn ; qprint_timen "Selecting \"US\"."
+  send_wrap "11"
+  expect_wrap [list "region US"] "select region in US menu" 10
+
+  qprintn ; qprint_timen "Selecting \"Central\"."
+  send_wrap "3"
+  expect_wrap [list $installer_screen_regex] "installation options screen" 10
+
+}
+
+
+proc software_selection {} {
+
+  # Set the base environment via the petitboot shell prompt
+  # "Software Selection" menu.
+
+  # Expectation is that we are starting at the "Installation" options
+  # screen.
+
+  dprintn ; dprint_executing
+
+  global spawn_id
+  global expect_out
+  global state
+  global installer_screen_regex
+
+  qprintn ; qprint_timen "Presumed to be at \"Installation\" screen."
+  qprintn ; qprint_timen "Software selection."
+  # Option 4). Software selection.
+  set expect_result 0
+  while { $expect_result != 1 } {
+    qprintn ; qprint_timen "Selecting \"Software selection\"."
+    send_wrap "4"
+    set expect_result [expect_wrap\
+      [list "Installation source needs to be set up first." \
+      "Base environment"] "base environment menu" 10 0]
+
+    switch $expect_result {
+      0 {
+        qprintn ; qprint_timen "Selecting \"continue\"."
+        send_wrap "c"
+        expect_wrap [list $installer_screen_regex] \
+        "installation options screen" 15
+      }
+      1 {
+        break
+      }
+    }
+  }
+
+  qprintn ; qprint_timen "Selecting \"Infrastructure Server\"."
+  send_wrap "2"
+  expect_wrap [list "Infrastructure"] "selected infrastructure" 15
+
+  qprintn ; qprint_timen "Selecting \"continue\"."
+  send_wrap "c"
+  expect_wrap [list $installer_screen_regex] "installation options screen" 15
+
+}
+
+
+proc root_password {} {
+
+  # Set the os root password via the petitboot shell prompt "Root password"
+  # option.
+
+  # Expectation is that we are starting at the "Installation" options screen.
+
+  dprintn ; dprint_executing
+
+  global spawn_id
+  global expect_out
+  global state
+  global os_password
+  global installer_screen_regex
+
+  qprintn ; qprint_timen "Presumed to be at \"Installation\" screen."
+  qprintn ; qprint_timen "Setting root password."
+
+  # Option 8). Root password.
+  qprintn ; qprint_timen "Selecting \"Root password\"."
+  send_wrap "8"
+  expect_wrap [list "Password:"] "root password prompt" 30
+
+  qprintn ; qprint_timen "Entering root password."
+  send_wrap "$os_password"
+  expect_wrap [list "confirm"] "comfirm root password prompt" 15
+
+  qprintn ; qprint_timen "Re-entering root password."
+  send_wrap "$os_password"
+  set expect_result [expect_wrap\
+    [list $installer_screen_regex "The password you have provided is weak"] \
+    "root password accepted" 10 0]
+  switch $expect_result {
+    0 {
+      break
+    }
+    1 {
+    qprintn ; qprint_timen "Confirming weak password."
+      send_wrap "yes"
+    }
+  }
+  expect_wrap [list $installer_screen_regex] "installation options screen" 10
+
+}
+
+
+proc install_os {} {
+
+  # Install an os on the machine.
+  global spawn_id
+  global expect_out
+  global petitboot_shell_prompt_regex
+  global installer_screen_regex
+  global ftp_username ftp_password os_repo_url
+  global os_host os_username os_password
+
+  lassign [get_host_name_ip $os_host 0] os_hostname short_host_name ip_address
+  set netmask [get_host_netmask $os_host $os_username $os_password 0]
+  set gateway [get_host_gateway $os_host $os_username $os_password 0]
+  set mac_address [get_host_mac_address $os_host $os_username $os_password "" 0]
+  set name_servers [get_host_name_servers $os_host $os_username $os_password "" 0]
+  set dns [lindex $name_servers 0]
+  set domain [get_host_domain $os_host $os_username $os_password 0]
+  exit_proc
+  # Go to shell and download files for installation
+  eval go_to_petitboot_shell
+  after 10000
+  set vmlinuz_url \
+    "ftp://$ftp_username:$ftp_password@$os_repo_url/ppc/ppc64/vmlinuz"
+  set initrd_url \
+    "ftp://$ftp_username:$ftp_password@$os_repo_url/ppc/ppc64/initrd.img"
+  send_wrap "wget -c $vmlinuz_url"
+  expect_wrap [list "vmlinuz *100%"] "wget vmlinuz file success" 30
+  send_wrap "wget -c $initrd_url"
+  expect_wrap [list "initrd.img *100%"] "wget initrd file success" 30
+
+  # Setup parms and run kexec.
+  set colon "::"
+  set squashfs_url \
+    "ftp://$ftp_username:$ftp_password@$os_repo_url/LiveOS/squashfs.img"
+  set kexec_args "kexec -l vmlinuz --initrd initrd.img\
+    --append='root=live:$squashfs_url \
+    repo=ftp://$ftp_username:$ftp_password@$os_repo_url rd.dm=0 rd.md=0\
+    nodmraid console=hvc0 ifname=net0:$mac_address\
+    ip=$os_host$colon$gateway:$netmask:$os_hostname:net0:none nameserver=$dns\
+    inst.text'"
+  send_wrap "$kexec_args"
+  dprintn ; dprint_vars expect_out
+  set expect_result [expect_wrap [list $petitboot_shell_prompt_regex]\
+    "the shell prompt" 10]
+
+  # Turn on autoboot.
+  send_wrap "nvram --update-config auto-boot?=true"
+  send_wrap "nvram --print-config | egrep 'auto\\-boot\\?=true'"
+
+  send_wrap "kexec -e"
+
+  # Begin installation process, go to settings screen.
+  set expect_result [expect_wrap [list "Starting installer"]\
+    "starting installer log" 900]
+  set expect_result [expect_wrap [list "Use text mode"]\
+    "install mode selection prompt" 120]
+  send_wrap "2"
+  expect_wrap [list $installer_screen_regex] "installation options screen" 15
+
+  installation_destination
+  time_settings
+  software_selection
+  root_password
+
+  # Now begin installation process.
+  set expect_result [expect_wrap\
+    [list $os_repo_url "Processing..."] \
+    "installation source processing" 10 0]
+
+  switch $expect_result {
+    0 {
+      break
+    }
+    1 {
+      expect_wrap [list $os_repo_url] "source processing complete" 240
+    }
+  }
+  send_wrap "b"
+  set expect_result [expect_wrap \
+    [list "Installation complete* Press return to quit"] \
+    "os installation complete message" 2000]
+  send_wrap ""; # Reboots to petitboot.
+  return
+
+}
+
+
 # Main
 
   gen_get_options $argv
@@ -462,6 +782,9 @@
   set petitboot_screen_regex "Petitboot"
   set cr_lf_regex "\[\n\r\]"
   set os_prompt_regex "(\\\[${os_username}@\[^ \]+ ~\\\]# )"
+  set petitboot_shell_prompt_regex "/ #"
+  set installer_screen_regex \
+  {Installation[\r\n].*Please make your choice from above.* to refresh\]: }
 
   dprintn ; dprint_dict state
 
@@ -473,8 +796,10 @@
   qprintn ; qprint_issuing
   eval ${cmd_buf}
 
-  set cmd_buf ${proc_name}
-  qprintn ; qprint_issuing
-  eval ${cmd_buf}
+  foreach proc_name $proc_names {
+    set cmd_buf ${proc_name}
+    qprintn ; qprint_issuing
+    eval ${cmd_buf}
+  }
 
-  exit_proc
+  exit_proc
\ No newline at end of file
diff --git a/lib/host.tcl b/lib/host.tcl
index 8db4325..365847e 100755
--- a/lib/host.tcl
+++ b/lib/host.tcl
@@ -3,7 +3,7 @@
 # This file provides valuable host and IP manipulation procedures such as
 # get_host_name_ip, etc.
 
-my_source [list cmd.tcl]
+my_source [list cmd.tcl data_proc.tcl]
 
 
 proc get_host_name_ip {host {quiet 1}} {
@@ -21,7 +21,7 @@
   # quiet                           Indicates whether status information
   #                                 should be printed.
 
-  if { ${quiet} } { set print_output 0 } else { set print_output 1 }
+  set print_output [expr !$quiet]
   lassign [cmd_fnc "host $host" "${quiet}" "" "${print_output}"] rc out_buf
   if { $rc != 0 } { return [list "" "" ""]}
 
@@ -45,3 +45,171 @@
 
 }
 
+
+proc get_host_domain {host username password {quiet 1}} {
+
+  # Return the domain name of the host.
+
+  # If this procedure is unable to get the requested information, it will
+  # print an error message to stderr and return a blank value.
+
+  # Description of argument(s):
+  # host                            The host name or IP address of the system
+  #                                 from which the information is to be
+  #                                 obtained.
+  # username                        The host username.
+  # password                        The host password.
+  # quiet                           Indicates whether status information
+  #                                 should be printed.
+
+  set print_output [expr !$quiet]
+  lassign [cmd_fnc \
+    "sshpass -p $password ssh -o StrictHostKeyChecking=no -k $username@$host\
+    'dnsdomainname'" ${quiet} "" ${print_output}] rc domain
+  return $domain
+
+}
+
+
+proc get_host_name_servers {host username password {quiet 1}} {
+
+  # Return a list of hostname or IP addresses.
+
+  # If this procedure is unable to get the requested information, it will
+  # print an error message to stderr and return a blank value.
+
+  # Description of argument(s):
+  # host                            The host name or IP address of the system
+  #                                 from which the information is to be
+  #                                 obtained.
+  # username                        The host username.
+  # password                        The host password.
+  # quiet                           Indicates whether status information
+  #                                 should be printed.
+
+  set print_output [expr !$quiet]
+  lassign [cmd_fnc "sshpass -p $password ssh -o StrictHostKeyChecking=no -k\
+    $username@$host\
+    grep -E '^[ ]*nameserver[ ]+' /etc/resolv.conf | awk '{print \$2}'"\
+    ${quiet} "" ${print_output}] rc name_servers
+  return [split $name_servers "\n"]
+
+}
+
+
+proc get_host_mac_address {host username password {interface {}} {quiet 1}} {
+
+  # Return the mac address of the host given a specific interface.
+
+  # If "interface" is left blank, it is set to the default interface.
+
+  # If this procedure is unable to get the requested information, it will
+  # print an error message to stderr and return a blank value.
+
+  # Description of argument(s):
+  # host                            The host name or IP address of the system
+  #                                 from which the information is to be
+  #                                 obtained.
+  # username                        The host username.
+  # password                        The host password.
+  # interface                       The target interface. Defaults to default
+  #                                 interface if not set.
+  # quiet                           Indicates whether status information
+  #                                 should be printed.
+
+  set print_output [expr !$quiet]
+  set_var_default interface [get_host_default_interface $host $username\
+    $password $quiet]
+  lassign [cmd_fnc "sshpass -p $password ssh -o StrictHostKeyChecking=no -k\
+    $username@$host 'cat /sys/class/net/$interface/address'" \
+    ${quiet} "" ${print_output}] rc mac_address
+  return $mac_address
+
+}
+
+
+proc get_host_gateway {host username password {quiet 1}} {
+
+  # Return the gateway of the host.
+
+  # If this procedure is unable to get the requested information, it will
+  # print an error message to stderr and return a blank value.
+
+  # Description of argument(s):
+  # host                            The host name or IP address of the system
+  #                                 from which the information is to be
+  #                                 obtained.
+  # username                        The host username.
+  # password                        The host password.
+  # quiet                           Indicates whether status information
+  #                                 should be printed.
+
+  set print_output [expr !$quiet]
+  lassign [cmd_fnc "sshpass -p $password ssh -o StrictHostKeyChecking=no -k\
+    $username@$host ip route | grep -i '^default' | awk '{print \$3}'" \
+    ${quiet} "" ${print_output}] rc gateway
+  return $gateway
+
+}
+
+
+proc get_host_default_interface {host username password {quiet 1} } {
+
+  # Return the default interface of the host interface.
+
+  # If this procedure is unable to get the requested information, it will
+  # print an error message to stderr and return a blank value.
+
+  # Description of argument(s):
+  # host                            The host name or IP address of the system
+  #                                 from which the information is to be
+  #                                 obtained.
+  # username                        The host username.
+  # password                        The host password.
+  # quiet                           Indicates whether status information
+  #                                 should be printed.
+
+  set print_output [expr !$quiet]
+  lassign [cmd_fnc "sshpass -p $password ssh -o StrictHostKeyChecking=no -k\
+    $username@$host ip route | grep -i '^default' | awk '{print \$5}'" \
+    ${quiet} "" ${print_output}] rc interface
+  return $interface
+
+}
+
+
+proc get_host_netmask {host username password {interface {}} {quiet 1}} {
+
+  # Return the subnet mask for the host.
+
+  # If this procedure is unable to get the requested information, it will
+  # print an error message to stderr and return a blank value.
+
+  # Description of argument(s):
+  # host                            The host name or IP address of the system
+  #                                 from which the information is to be
+  #                                 obtained.
+  # username                        The host username.
+  # password                        The host password.
+  # interface                       The target interface. Defaults to default
+  #                                 interface if not set.
+  # quiet                           Indicates whether status information
+  #                                 should be printed.
+
+  set print_output [expr !$quiet]
+  set sshpass_cmd \
+    "sshpass -p $password ssh -o StrictHostKeyChecking=no -k $username@$host"
+  set_var_default interface [get_host_default_interface $host $username\
+    $password $quiet]
+  lassign [cmd_fnc \
+    "$sshpass_cmd ifconfig $interface | grep -i mask"\
+    ${quiet} "" ${print_output}] rc out_buf
+  if {[string match *broadcast* $out_buf]} {
+    set mask_cmd "ifconfig $interface | grep ask | awk '{print \$4}'"
+  } else {
+    set mask_cmd "ifconfig $interface | grep ask | cut -d ':' -f 4"
+  }
+  lassign [cmd_fnc "$sshpass_cmd $mask_cmd" $quiet] rc netmask
+  return $netmask
+
+}