| 1 | [[PageOutline]] |
| 2 | |
| 3 | For the [wiki:PlasticSlices Plastic Slices] project, we used a variety of simplistic tools to make it easier to manage slices and experiments. |
| 4 | |
| 5 | Many of the things we did here were to simplify the task of running ten slices simultaneously, but many of them are useful even if you're only running one slice. |
| 6 | |
| 7 | ''FIXME: Much of this page is still under construction.'' |
| 8 | |
| 9 | = rspecs = |
| 10 | |
| 11 | For each slice, we kept a directory of rspecs for the slice in a Subversion repository. The MyPLC rspecs were the same for each slice, so we actually stored them in a 'misc' directory and then created symlinks pointing to them in the per-slice directories. The OpenFlow rspecs were different for each slice -- very similar to each other, but e.g. the IP subnet, the URL of the controller, etc, were different. |
| 12 | |
| 13 | A copy of the plastic-101 and plastic-102 directories are here. (''FIXME: Figure out the best way to put them here. GENI wiki SVN? Need to strip out passwords, so we can't have them actually live here, this is just a snapshot. Sub-pages?'') |
| 14 | |
| 15 | We could then use these directories as input to omni commands to operate on "all the slivers in a slice", conceptually, e.g. with |
| 16 | |
| 17 | {{{ |
| 18 | for rspec in ~/rspecs/reservation/$slicename/* ; do <something> ; done |
| 19 | }}} |
| 20 | |
| 21 | such as the omni commands below. |
| 22 | |
| 23 | = omni = |
| 24 | |
| 25 | We used the command-line tool 'omni' to manage all of the slices and slivers. |
| 26 | |
| 27 | == somni == |
| 28 | |
| 29 | Short for "setup omni", we defined a bash function to set some variables for use by subsequent omni commands: |
| 30 | |
| 31 | {{{ |
| 32 | somni () { slicename=$1 ; rspec=$2 ; am=$(grep AM: $rspec | sed -e 's/^AM: //') ; } |
| 33 | }}} |
| 34 | |
| 35 | See below for usage examples. |
| 36 | |
| 37 | == Creating slices == |
| 38 | |
| 39 | We used these loops to create the ten plastic-* slices, and renew them until August 4th: |
| 40 | |
| 41 | {{{ |
| 42 | for slicename in plastic-{101..110} ; do omni createslice $slicename ; done |
| 43 | for slicename in plastic-{101..110} ; do omni renewslice $slicename $(date +%Y%m%dT%H:%M:%S -d "August 4 15:00") ; done |
| 44 | }}} |
| 45 | |
| 46 | == Creating slivers == |
| 47 | |
| 48 | We then used the rspec directories to create all of the slivers in each slice: |
| 49 | |
| 50 | {{{ |
| 51 | for slicename in plastic-{101..110} |
| 52 | do |
| 53 | for rspec in ~/rspecs/reservation/$slicename/* |
| 54 | do |
| 55 | somni $slicename $rspec |
| 56 | omni -n -a $am createsliver $slicename $rspec |
| 57 | done |
| 58 | done |
| 59 | }}} |
| 60 | |
| 61 | == Renewing slivers == |
| 62 | |
| 63 | We also used the rspec directories to renew all of the MyPLC slivers in each slice: |
| 64 | |
| 65 | {{{ |
| 66 | for slicename in plastic-{101..110} |
| 67 | do |
| 68 | for rspec in ~/rspecs/reservation/$slicename/myplc-*rspec |
| 69 | do somni $slicename $rspec |
| 70 | omni -n -a $am renewsliver $slicename $(date +%Y%m%dT%H:%M:%S -d "August 4 15:00") |
| 71 | done |
| 72 | done |
| 73 | }}} |
| 74 | |
| 75 | = Managing logins = |
| 76 | |
| 77 | Once we had our slivers, it was handy to have a way to run commands on all of the compute resources in parallel, or copy files to or from all of them. We did that by creating a file for each slice with the logins for the slivers in that slice, which we'd then feed as input to rsync or shmux. |
| 78 | |
| 79 | == Specify which logins to use == |
| 80 | |
| 81 | To do something with all the logins in a slice, we'd do: |
| 82 | |
| 83 | {{{ |
| 84 | logins=$(cat ~/plastic-slices/logins/logins-plastic-101.txt) |
| 85 | }}} |
| 86 | |
| 87 | We'd sometimes use grep to use only a subset, e.g. all the ones at Clemson: |
| 88 | |
| 89 | {{{ |
| 90 | logins=$(grep -h clemson ~/plastic-slices/logins/logins-plastic-101.txt) |
| 91 | }}} |
| 92 | |
| 93 | We often wanted to do something with the logins in multiple slices; for all logins on all slices, we'd do |
| 94 | |
| 95 | {{{ |
| 96 | logins=$(cat ~/plastic-slices/logins/logins-plastic-{101..110}.txt) |
| 97 | }}} |
| 98 | |
| 99 | and for a subset (e.g. all the ones for Clemson), we'd do something like |
| 100 | |
| 101 | {{{ |
| 102 | logins=$(grep -h clemson ~/plastic-slices/logins/logins-plastic-{101..110}.txt) |
| 103 | }}} |
| 104 | |
| 105 | You can also set $logins by hand, of course. |
| 106 | |
| 107 | == Run a command on all of those logins == |
| 108 | |
| 109 | We'd sometimes use a 'for' loop to run a command on each login, one at a time, like this one, which enables non-interactive sudo without a terminal (which is disabled by default): |
| 110 | |
| 111 | {{{ |
| 112 | for login in $logins ; do ssh -t $login sudo sed -i -e 's/!visiblepw/visiblepw/' /etc/sudoers ; done |
| 113 | }}} |
| 114 | |
| 115 | More often, we used 'shmux' to run the same command on each login in parallel. We aliased 'shmux' to include some useful options: |
| 116 | |
| 117 | {{{ |
| 118 | alias shmux='shmux -Sall -m -B -T 15' |
| 119 | }}} |
| 120 | |
| 121 | We then used it to enable cron (which we can do now that non-interactive sudo is enabled): |
| 122 | |
| 123 | {{{ |
| 124 | shmux -c 'sudo chkconfig crond on && sudo service crond start' $logins |
| 125 | }}} |
| 126 | |
| 127 | And to install 'screen': |
| 128 | |
| 129 | {{{ |
| 130 | shmux -c 'sudo yum -y install screen' $logins |
| 131 | }}} |
| 132 | |
| 133 | We installed a crontab for each login (after copying the file to each login, see below): |
| 134 | |
| 135 | {{{ |
| 136 | shmux -c 'crontab $HOME/.crontab' $logins |
| 137 | }}} |
| 138 | |
| 139 | After we were done running experiments, we checked to make sure nothing unexpected had been left running: |
| 140 | |
| 141 | {{{ |
| 142 | shmux -c "ps -efwww | egrep -i -v '(grep|cron|PID|ping|ps)' || true" $logins |
| 143 | }}} |
| 144 | |
| 145 | == Transfer files to all of those logins == |
| 146 | |
| 147 | We copied up a common directory of dotfiles (including the crontab mentioned above): |
| 148 | |
| 149 | {{{ |
| 150 | for login in $logins ; do rsync -a ~/plastic-slices/dotfiles/ $login: && echo $login ; done |
| 151 | }}} |
| 152 | |
| 153 | (We echo the login name after each one finishes just so we can tell that it's making progress.) |
| 154 | |
| 155 | We also sometimes did this in parallel, by telling the for loop to run the commands in the background (replacing the final ; with an &): |
| 156 | |
| 157 | {{{ |
| 158 | for login in $logins ; do rsync -a ~/plastic-slices/dotfiles/ $login: && echo $login & done |
| 159 | }}} |
| 160 | |
| 161 | If you had a login-specific directory of dotfiles, you could use that too: |
| 162 | |
| 163 | {{{ |
| 164 | for login in $logins ; do rsync -a ~/plastic-slices/dotfiles/$login $login: && echo $login & done |
| 165 | }}} |
| 166 | |
| 167 | We also used this to copy files back from each login, such as to pull down the screen log from each login: |
| 168 | |
| 169 | {{{ |
| 170 | for login in $logins ; do echo "getting $login" ; rsync -a $login:screenlog.0 $login.log ; done |
| 171 | }}} |
| 172 | |
| 173 | = Running experiments = |
| 174 | |
| 175 | As of Baseline 5, we used two layers of 'screen' processes to run the experiments. First, we ran screen on a local machine for each slice, with a virtual terminal for each login. We had a .screenrc file for each slice to automate this. (''FIXME: Include or link to these here.'') |
| 176 | |
| 177 | Then, on each login, we ran 'screen' with a single virtual terminal, so that (a) if the connection from the local system to the remote login got disconnected, we could log back in and reconnect to the screen process; (b) we could use screen's logging functionality to capture all the output from the experiment (and retrieve it later). |
| 178 | |
| 179 | == Launch them all == |
| 180 | |
| 181 | We used this to launch them, one at a time: |
| 182 | |
| 183 | {{{ |
| 184 | for slice in plastic-{101..110} ; do screen -S $slice -c ~/plastic-slices/screenrc/screenrc-$slice ; done |
| 185 | }}} |
| 186 | |
| 187 | Detach from each after it launches, and the next will launch. |
| 188 | |
| 189 | == Connect to one == |
| 190 | |
| 191 | We could then connect to them, plastic-101 in this example: |
| 192 | |
| 193 | {{{ |
| 194 | screen -r plastic-101 |
| 195 | }}} |
| 196 | |
| 197 | The '-S $slice' in the initial launch command above is what enables this handy trick -- it's otherwise pretty hard to keep track of which 'screen' process corresponds to which slice. |
| 198 | |
| 199 | == Start screen running and logging on a remote plnode == |
| 200 | |
| 201 | We had an alias for this: |
| 202 | |
| 203 | {{{ |
| 204 | experiment-start |
| 205 | }}} |
| 206 | |
| 207 | This was an alias in .bashrc: |
| 208 | |
| 209 | {{{ |
| 210 | alias experiment-start='sudo rm -f screenlog.0 ; sudo script -c screen /dev/null' |
| 211 | }}} |
| 212 | |
| 213 | That oddness is necessary because 'screen' on a MyPLC plnode can't handle long usernames, so we needed to become root in order to launch it... But if you just do 'sudo screen', it complains "Cannot access '/dev/pts/0': No such file or directory", because you're in a VM on the plnode, so the 'script ... /dev/null' trick avoids that problem (by using the 'script' command to redirect output to /dev/null). And then, |
| 214 | |
| 215 | We then had a .screenrc file containing |
| 216 | |
| 217 | {{{ |
| 218 | screen -L su - $SUDO_USER |
| 219 | }}} |
| 220 | |
| 221 | on the remote plnode, because we didn't actually want to run the experiments as root, so we open a window running as the original user. |
| 222 | |
| 223 | == Reconnect to a screen session on a remote plnode == |
| 224 | |
| 225 | {{{ |
| 226 | reconnect |
| 227 | }}} |
| 228 | |
| 229 | This is an alias in .bashrc: |
| 230 | |
| 231 | {{{ |
| 232 | alias reconnect='sudo script -c "screen -dr" /dev/null' |
| 233 | }}} |
| 234 | |
| 235 | which reconnects to one of the screens created earlier. |
| 236 | |
| 237 | == Dump hardcopy logs == |
| 238 | |
| 239 | In Baseline 4, we just ran a local 'screen' process, and used somewhat different .screenrc files, to create long scrollback buffers and then dump them to disk with screen's 'hardcopy' function. |
| 240 | |
| 241 | This dumps the logs, removes zero-length logs (from screen windows that didn't exist), and removes the blank lines from the top and bottom of each file. |
| 242 | |
| 243 | {{{ |
| 244 | cd ~/plastic-slices/baseline-logs/baseline-4 |
| 245 | for slice in plastic-{101..110} ; do for i in {0..13} ; do screen -S $slice -p $i -X hardcopy -h $slice-hardcopy-$i.log ; sleep 1 ; done ; done |
| 246 | for i in * ; do test -s $i || rm $i ; done |
| 247 | sed -i -e '/./,$!d' * |
| 248 | sed -i -e :a -e '/^\n*$/{$d;N;ba' -e '}' * |
| 249 | }}} |