Jeremy Ronquillo | b27ce4c | 2017-07-17 12:41:28 -0700 | [diff] [blame] | 1 | """ |
Jeremy Ronquillo | 23fb216 | 2017-09-15 14:59:57 -0700 | [diff] [blame] | 2 | Copyright 2016 Open Networking Foundation ( ONF ) |
Jeremy Ronquillo | b27ce4c | 2017-07-17 12:41:28 -0700 | [diff] [blame] | 3 | |
| 4 | Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>, |
| 5 | the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>, |
| 6 | or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg> |
| 7 | |
| 8 | TestON is free software: you can redistribute it and/or modify |
| 9 | it under the terms of the GNU General Public License as published by |
| 10 | the Free Software Foundation, either version 2 of the License, or |
Jeremy Ronquillo | 23fb216 | 2017-09-15 14:59:57 -0700 | [diff] [blame] | 11 | ( at your option ) any later version. |
Jeremy Ronquillo | b27ce4c | 2017-07-17 12:41:28 -0700 | [diff] [blame] | 12 | |
| 13 | TestON is distributed in the hope that it will be useful, |
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | GNU General Public License for more details. |
| 17 | |
| 18 | You should have received a copy of the GNU General Public License |
| 19 | along with TestON. If not, see <http://www.gnu.org/licenses/>. |
| 20 | """ |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 21 | "Functions for using the SimpleHTTPServer python module" |
| 22 | import re |
| 23 | |
Jeremy Ronquillo | 23fb216 | 2017-09-15 14:59:57 -0700 | [diff] [blame] | 24 | |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 25 | class Server(): |
| 26 | |
| 27 | def __init__( self ): |
| 28 | self.default = '' |
| 29 | self.PID = -1 |
| 30 | self.component = None |
| 31 | self.rootDir = None |
| 32 | |
| 33 | def __del__( self ): |
| 34 | self.stop() |
| 35 | |
| 36 | def start( self, component, rootDir, port=8000, logDir=None ): |
| 37 | """ |
| 38 | Start SimpleHTTPServer as a background process from rootDir on the |
| 39 | given component. The webserver will listen on port and if specified, |
| 40 | output will be redirected to logDir. |
| 41 | |
| 42 | Arguments: |
| 43 | - component = The TestON component handle to start the webserver on |
| 44 | - rootDir = The root directory for the web content |
| 45 | - port = The port number for the webserver to listen on. Defaults to 8000 |
| 46 | - logDir = If specified, the output of the webserver will be redirected |
| 47 | to this file. Note that this should be either an absolute path |
| 48 | or relative to rootDir. |
| 49 | Returns: |
| 50 | main.TRUE if the command succedes or main.FALSE if there is an error. |
| 51 | """ |
| 52 | retValue = main.TRUE |
| 53 | self.rootDir = rootDir |
| 54 | try: |
| 55 | # Save component for this instance so other functions can use it |
| 56 | self.component = component |
| 57 | main.log.info( "Starting SimpleHTTPServer on " + component.name ) |
| 58 | if component.handle: |
| 59 | handle = component.handle |
| 60 | # cd to rootDir |
| 61 | handle.sendline( "cd " + str( rootDir ) ) |
Jon Hall | cd2604f | 2018-04-12 12:39:48 -0700 | [diff] [blame] | 62 | handle.expect( component.prompt ) |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 63 | # Start server |
| 64 | cmd = "python -m SimpleHTTPServer {}".format( port ) |
| 65 | if logDir: |
| 66 | cmd += " &> {}".format( logDir ) # pipe all output to a file |
| 67 | else: |
Jeremy Ronquillo | 23fb216 | 2017-09-15 14:59:57 -0700 | [diff] [blame] | 68 | cmd += "&> {dev/null}" # Throw away all output |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 69 | cmd += " &" |
| 70 | handle.sendline( cmd ) |
Jon Hall | cd2604f | 2018-04-12 12:39:48 -0700 | [diff] [blame] | 71 | handle.expect( component.prompt ) |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 72 | response = handle.before |
| 73 | # Return to home dir |
| 74 | handle.sendline( "cd " + component.home ) |
Jon Hall | cd2604f | 2018-04-12 12:39:48 -0700 | [diff] [blame] | 75 | handle.expect( component.prompt ) |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 76 | response += handle.before |
| 77 | if "Exit" in response: |
| 78 | main.log.error( "Error starting server. Check server log for details" ) |
| 79 | main.log.debug( handle.before ) |
Jon Hall | cd2604f | 2018-04-12 12:39:48 -0700 | [diff] [blame] | 80 | # Show the log |
| 81 | handle.sendline( "cat {}".format( logDir )) |
| 82 | handle.expect( component.prompt ) |
| 83 | main.log.debug( handle.before ) |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 84 | retValue = main.FALSE |
| 85 | # capture PID for later use |
Jeremy Ronquillo | 23fb216 | 2017-09-15 14:59:57 -0700 | [diff] [blame] | 86 | # EX: [ 1 ] 67987 |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 87 | match = re.search( "\[\d\] (?P<PID>\d+)", response ) |
| 88 | if match: |
| 89 | self.PID = match.group( "PID" ) |
| 90 | else: |
| 91 | main.log.warn( "Could not find PID" ) |
| 92 | else: |
| 93 | main.log.error( "Component handle is not set" ) |
| 94 | retValue = main.FALSE |
| 95 | except Exception: |
| 96 | main.log.exception( "Error starting web server" ) |
| 97 | retValue = main.FALSE |
| 98 | return retValue |
| 99 | |
| 100 | def stop( self ): |
| 101 | """ |
| 102 | Kills the process of the server. Note that this function must be run |
| 103 | from the same instance of the server class that the server was started |
| 104 | on. |
| 105 | """ |
| 106 | retValue = main.TRUE |
| 107 | try: |
| 108 | main.log.info( "Stopping Server." ) |
| 109 | assert self.component, "Component not specified" |
| 110 | assert self.PID, "PID not found" |
| 111 | if self.component.handle: |
| 112 | handle = self.component.handle |
| 113 | cmd = "sudo kill {}".format( self.PID ) |
| 114 | handle.sendline( cmd ) |
Jon Hall | cd2604f | 2018-04-12 12:39:48 -0700 | [diff] [blame] | 115 | handle.expect( component.prompt ) |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 116 | # TODO: What is bad output? cannot sudo? |
| 117 | else: |
| 118 | main.log.error( "Component handle is not set" ) |
| 119 | retValue = main.FALSE |
| 120 | except Exception: |
| 121 | main.log.exception( "Error stopping web server" ) |
| 122 | retValue = main.FALSE |
| 123 | return retValue |
| 124 | |
| 125 | def generateFile( self, nodes, equal=False, filename="cluster.json" ): |
| 126 | """ |
| 127 | Generate custom metadata file in the root directory using the custom |
| 128 | onos-gen-partitions file which should also be located in the root |
| 129 | directory. |
| 130 | |
| 131 | Note that this function needs to be run after the start function has |
| 132 | been called for this instance. |
| 133 | |
| 134 | Arguments: |
| 135 | - nodes = The number of ONOS nodes to include in the cluster. Will |
| 136 | include nodes in ascending order, I.E. OC1, OC2, etc |
| 137 | |
| 138 | Optional Arguments: |
| 139 | - equal = Specifies whether all nodes should participate in every |
| 140 | partition. Defaults to False. |
| 141 | - filename = The name of the file to save the cluster metadata to. |
| 142 | Defaults to "cluster.json". |
| 143 | Returns: |
| 144 | main.TRUE if the command succedes or main.FALSE if there is an error. |
| 145 | """ |
| 146 | retValue = main.TRUE |
| 147 | try: |
| 148 | if self.component.handle: |
| 149 | assert self.component, "Component not specified. Please start the server first" |
| 150 | assert self.rootDir, "Root directory not found" |
| 151 | handle = self.component.handle |
| 152 | # cd to rootDir |
| 153 | handle.sendline( "cd " + str( self.rootDir ) ) |
Jon Hall | cd2604f | 2018-04-12 12:39:48 -0700 | [diff] [blame] | 154 | handle.expect( component.prompt ) |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 155 | cmd = "./onos-gen-partitions {} {} ".format( filename, nodes ) |
| 156 | if equal: |
| 157 | cmd += "-e" |
| 158 | handle.sendline( cmd ) |
Jon Hall | cd2604f | 2018-04-12 12:39:48 -0700 | [diff] [blame] | 159 | handle.expect( component.prompt ) |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 160 | response = handle.before |
| 161 | # Return to home dir |
| 162 | handle.sendline( "cd " + self.component.home ) |
Jon Hall | cd2604f | 2018-04-12 12:39:48 -0700 | [diff] [blame] | 163 | handle.expect( component.prompt ) |
Jon Hall | 9ebd1bd | 2016-04-19 01:37:17 -0700 | [diff] [blame] | 164 | response += handle.before |
| 165 | if "Traceback" in response: |
| 166 | main.log.error( handle.before ) |
| 167 | retValue = main.FALSE |
| 168 | else: |
| 169 | main.log.error( "Component handle is not set" ) |
| 170 | retValue = main.FALSE |
| 171 | except Exception: |
| 172 | main.log.exception( "Error generating metadata file" ) |
| 173 | return retValue |