Thomas Vachuska
Committed by Gerrit Code Review

Initial implementation of shared test cell warden.

Change-Id: Ia973d514fe1dd11ffe4cdb7c902cc43a9c2eb626
...@@ -103,10 +103,41 @@ function setPrimaryInstance { ...@@ -103,10 +103,41 @@ function setPrimaryInstance {
103 echo $OCI 103 echo $OCI
104 } 104 }
105 105
106 +# ON.Lab shared test cell warden address
107 +export CELL_WARDEN="10.254.1.19"
108 +
106 # Applies the settings in the specified cell file or lists current cell definition 109 # Applies the settings in the specified cell file or lists current cell definition
107 # if no cell file is given. 110 # if no cell file is given.
108 function cell { 111 function cell {
109 - if [ -n "$1" ]; then 112 + cell=$1
113 + case "$cell" in
114 + "borrow")
115 + aux="/tmp/cell-$$"
116 + curl -sS -X POST "http://$CELL_WARDEN:4321/?user=$(id -un)&duration=${2:-60}" \
117 + -d "$(cat ~/.ssh/id_rsa.pub)" > $aux
118 + . $aux
119 + rm -f $aux
120 + export ONOS_INSTANCES=$(env | grep 'OC[0-9]*=' | sort | cut -d= -f2)
121 + setPrimaryInstance 1 >/dev/null
122 + cell
123 + ;;
124 + "return")
125 + curl -sS -X DELETE "http://$CELL_WARDEN:4321/?user=$(id -un)"
126 + ;;
127 +
128 + "status")
129 + curl -sS "http://$CELL_WARDEN:4321/"
130 + ;;
131 +
132 + "")
133 + env | egrep "ONOS_CELL"
134 + env | egrep "OCI"
135 + env | egrep "OC[0-9]+" | sort
136 + env | egrep "OC[NT]"
137 + env | egrep "ONOS_" | egrep -v 'ONOS_ROOT|ONOS_CELL|ONOS_INSTANCES' | sort
138 + ;;
139 +
140 + *)
110 [ ! -f $ONOS_ROOT/tools/test/cells/$1 ] && \ 141 [ ! -f $ONOS_ROOT/tools/test/cells/$1 ] && \
111 echo "No such cell: $1" >&2 && return 1 142 echo "No such cell: $1" >&2 && return 1
112 unset ONOS_CELL ONOS_NIC ONOS_IP ONOS_APPS ONOS_BOOT_FEATURES 143 unset ONOS_CELL ONOS_NIC ONOS_IP ONOS_APPS ONOS_BOOT_FEATURES
...@@ -121,16 +152,10 @@ function cell { ...@@ -121,16 +152,10 @@ function cell {
121 export ONOS_INSTANCES=$(env | grep 'OC[0-9]*=' | sort | cut -d= -f2) 152 export ONOS_INSTANCES=$(env | grep 'OC[0-9]*=' | sort | cut -d= -f2)
122 setPrimaryInstance 1 >/dev/null 153 setPrimaryInstance 1 >/dev/null
123 cell 154 cell
124 - else 155 + esac
125 - env | egrep "ONOS_CELL"
126 - env | egrep "OCI"
127 - env | egrep "OC[0-9]+" | sort
128 - env | egrep "OC[NT]"
129 - env | egrep "ONOS_" | egrep -v 'ONOS_ROOT|ONOS_CELL|ONOS_INSTANCES' | sort
130 - fi
131 } 156 }
132 157
133 -cell $ONOS_CELL > /dev/null 158 +[ -n "$ONOS_CELL" ] && cell $ONOS_CELL > /dev/null
134 159
135 # Lists available cells 160 # Lists available cells
136 function cells { 161 function cells {
......
...@@ -40,7 +40,7 @@ complete -F _stl-opts stl ...@@ -40,7 +40,7 @@ complete -F _stl-opts stl
40 function _cell-opts () { 40 function _cell-opts () {
41 local cur=${COMP_WORDS[COMP_CWORD]} 41 local cur=${COMP_WORDS[COMP_CWORD]}
42 if [ $COMP_CWORD -eq 1 ]; then 42 if [ $COMP_CWORD -eq 1 ]; then
43 - COMPREPLY=( $( compgen -W "$(cd $ONOS_ROOT/tools/test/cells && ls -1)" -- $cur ) ) 43 + COMPREPLY=( $( compgen -W "$(cd $ONOS_ROOT/tools/test/cells && ls -1) borrow return status" -- $cur ) )
44 fi 44 fi
45 } 45 }
46 46
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015-present Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0"
18 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
20 + <modelVersion>4.0.0</modelVersion>
21 +
22 + <parent>
23 + <groupId>org.onosproject</groupId>
24 + <artifactId>onlab-utils</artifactId>
25 + <version>1.6.0-SNAPSHOT</version>
26 + <relativePath>../pom.xml</relativePath>
27 + </parent>
28 +
29 + <artifactId>onlab-warden</artifactId>
30 + <packaging>jar</packaging>
31 +
32 + <description>System Test Cell Warden</description>
33 +
34 + <dependencies>
35 + <dependency>
36 + <groupId>org.eclipse.jetty</groupId>
37 + <artifactId>jetty-server</artifactId>
38 + <version>8.1.18.v20150929</version>
39 + </dependency>
40 + <dependency>
41 + <groupId>org.eclipse.jetty</groupId>
42 + <artifactId>jetty-servlet</artifactId>
43 + <version>8.1.18.v20150929</version>
44 + </dependency>
45 + </dependencies>
46 +
47 + <build>
48 + <plugins>
49 + <plugin>
50 + <groupId>org.apache.maven.plugins</groupId>
51 + <artifactId>maven-shade-plugin</artifactId>
52 + <version>2.4.3</version>
53 + <configuration>
54 + <transformers>
55 + <transformer
56 + implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
57 + <mainClass>org.onlab.warden.Main</mainClass>
58 + </transformer>
59 + </transformers>
60 + <filters>
61 + <filter>
62 + <artifact>*:*</artifact>
63 + <excludes>
64 + <exclude>META-INF/*.SF</exclude>
65 + <exclude>META-INF/*.DSA</exclude>
66 + <exclude>META-INF/*.RSA</exclude>
67 + </excludes>
68 + </filter>
69 + </filters>
70 + </configuration>
71 + <executions>
72 + <execution>
73 + <phase>package</phase>
74 + <goals>
75 + <goal>shade</goal>
76 + </goals>
77 + </execution>
78 + </executions>
79 + </plugin>
80 + </plugins>
81 + </build>
82 +
83 +</project>
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onlab.warden;
18 +
19 +import org.eclipse.jetty.server.Server;
20 +import org.eclipse.jetty.servlet.ServletHandler;
21 +import org.eclipse.jetty.util.log.Logger;
22 +
23 +/**
24 + * Main program for executing scenario test warden.
25 + */
26 +public final class Main {
27 +
28 + // Public construction forbidden
29 + private Main(String[] args) {
30 + }
31 +
32 + /**
33 + * Main entry point for the cell warden.
34 + *
35 + * @param args command-line arguments
36 + */
37 + public static void main(String[] args) {
38 + Main main = new Main(args);
39 + main.run();
40 + }
41 +
42 + // Runs the warden processing
43 + private void run() {
44 + startWebServer();
45 + }
46 +
47 + // Initiates a web-server.
48 + private static void startWebServer() {
49 + WardenServlet.warden = new Warden();
50 + org.eclipse.jetty.util.log.Log.setLog(new NullLogger());
51 + Server server = new Server(4321);
52 + ServletHandler handler = new ServletHandler();
53 + server.setHandler(handler);
54 + handler.addServletWithMapping(WardenServlet.class, "/*");
55 + try {
56 + server.start();
57 + } catch (Exception e) {
58 + print("Warden already active...");
59 + }
60 + }
61 +
62 + private static void print(String s) {
63 + System.out.println(s);
64 + }
65 +
66 + // Logger to quiet Jetty down
67 + private static class NullLogger implements Logger {
68 + @Override
69 + public String getName() {
70 + return "quiet";
71 + }
72 +
73 + @Override
74 + public void warn(String msg, Object... args) {
75 + }
76 +
77 + @Override
78 + public void warn(Throwable thrown) {
79 + }
80 +
81 + @Override
82 + public void warn(String msg, Throwable thrown) {
83 + }
84 +
85 + @Override
86 + public void info(String msg, Object... args) {
87 + }
88 +
89 + @Override
90 + public void info(Throwable thrown) {
91 + }
92 +
93 + @Override
94 + public void info(String msg, Throwable thrown) {
95 + }
96 +
97 + @Override
98 + public boolean isDebugEnabled() {
99 + return false;
100 + }
101 +
102 + @Override
103 + public void setDebugEnabled(boolean enabled) {
104 + }
105 +
106 + @Override
107 + public void debug(String msg, Object... args) {
108 + }
109 +
110 + @Override
111 + public void debug(Throwable thrown) {
112 + }
113 +
114 + @Override
115 + public void debug(String msg, Throwable thrown) {
116 + }
117 +
118 + @Override
119 + public Logger getLogger(String name) {
120 + return this;
121 + }
122 +
123 + @Override
124 + public void ignore(Throwable ignored) {
125 + }
126 + }
127 +
128 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onlab.warden;
18 +
19 +import static com.google.common.base.Preconditions.checkState;
20 +
21 +/**
22 + * Cell reservation record.
23 + */
24 +final class Reservation {
25 +
26 + final String cellName;
27 + final String userName;
28 + final long time;
29 + final int duration;
30 +
31 + // Creates a new reservation record
32 + Reservation(String cellName, String userName, long time, int duration) {
33 + this.cellName = cellName;
34 + this.userName = userName;
35 + this.time = time;
36 + this.duration = duration;
37 + }
38 +
39 + /**
40 + * Decodes reservation record from the specified line.
41 + *
42 + * @param line string line
43 + */
44 + Reservation(String line) {
45 + String[] fields = line.trim().split("\t");
46 + checkState(fields.length == 4, "Incorrect reservation encoding");
47 + this.cellName = fields[0];
48 + this.userName = fields[1];
49 + this.time = Long.parseLong(fields[2]);
50 + this.duration = Integer.parseInt(fields[3]);
51 + }
52 +
53 + /**
54 + * Encodes reservation record into a string line.
55 + *
56 + * @return encoded string
57 + */
58 + String encode() {
59 + return String.format("%s\t%s\t%s\t%s\n", cellName, userName, time, duration);
60 + }
61 +
62 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onlab.warden;
18 +
19 +import com.google.common.collect.ImmutableList;
20 +import com.google.common.collect.ImmutableSet;
21 +import com.google.common.io.ByteStreams;
22 +
23 +import java.io.File;
24 +import java.io.FileInputStream;
25 +import java.io.FileOutputStream;
26 +import java.io.IOException;
27 +import java.io.InputStream;
28 +import java.io.PrintWriter;
29 +import java.text.SimpleDateFormat;
30 +import java.util.Date;
31 +import java.util.HashSet;
32 +import java.util.List;
33 +import java.util.Random;
34 +import java.util.Set;
35 +import java.util.Timer;
36 +import java.util.TimerTask;
37 +import java.util.concurrent.TimeUnit;
38 +import java.util.regex.Matcher;
39 +import java.util.regex.Pattern;
40 +
41 +import static com.google.common.base.Preconditions.*;
42 +
43 +/**
44 + * Warden for tracking use of shared test cells.
45 + */
46 +class Warden {
47 +
48 + private static final String CELL_NOT_NULL = "Cell name cannot be null";
49 + private static final String USER_NOT_NULL = "User name cannot be null";
50 + private static final String KEY_NOT_NULL = "User key cannot be null";
51 + private static final String UTF_8 = "UTF-8";
52 + private static final long TIMEOUT = 3;
53 +
54 + private static final String AUTHORIZED_KEYS = "authorized_keys";
55 +
56 + private static final int MAX_MINUTES = 240; // 4 hours max
57 + private static final int MINUTE = 60_000; // 1 minute
58 +
59 + private final File log = new File("warden.log");
60 +
61 + private final File cells = new File("cells");
62 + private final File supported = new File(cells, "supported");
63 + private final File reserved = new File(cells, "reserved");
64 +
65 + private final Random random = new Random();
66 +
67 + private final Timer timer = new Timer("cell-pruner", true);
68 +
69 + /**
70 + * Creates a new cell warden.
71 + */
72 + Warden() {
73 + random.setSeed(System.currentTimeMillis());
74 + timer.schedule(new Reposessor(), MINUTE / 4, MINUTE);
75 + }
76 +
77 + /**
78 + * Returns list of names of supported cells.
79 + *
80 + * @return list of cell names
81 + */
82 + Set<String> getCells() {
83 + String[] list = supported.list();
84 + return list != null ? ImmutableSet.copyOf(list) : ImmutableSet.of();
85 + }
86 +
87 + /**
88 + * Returns list of names of available cells.
89 + *
90 + * @return list of cell names
91 + */
92 + Set<String> getAvailableCells() {
93 + Set<String> available = new HashSet<>(getCells());
94 + available.removeAll(getReservedCells());
95 + return ImmutableSet.copyOf(available);
96 + }
97 +
98 + /**
99 + * Returns list of names of reserved cells.
100 + *
101 + * @return list of cell names
102 + */
103 + Set<String> getReservedCells() {
104 + String[] list = reserved.list();
105 + return list != null ? ImmutableSet.copyOf(list) : ImmutableSet.of();
106 + }
107 +
108 +
109 + /**
110 + * Returns reservation for the specified user.
111 + *
112 + * @param userName user name
113 + * @return cell reservation record or null if user does not have one
114 + */
115 + Reservation currentUserReservation(String userName) {
116 + checkNotNull(userName, USER_NOT_NULL);
117 + for (String cellName : getReservedCells()) {
118 + Reservation reservation = currentCellReservation(cellName);
119 + if (reservation != null && userName.equals(reservation.userName)) {
120 + return reservation;
121 + }
122 + }
123 + return null;
124 + }
125 +
126 + /**
127 + * Returns the name of the user who reserved the given cell.
128 + *
129 + * @param cellName cell name
130 + * @return cell reservation record or null if cell is not reserved
131 + */
132 + Reservation currentCellReservation(String cellName) {
133 + checkNotNull(cellName, CELL_NOT_NULL);
134 + File cellFile = new File(reserved, cellName);
135 + if (!cellFile.exists()) {
136 + return null;
137 + }
138 + try (InputStream stream = new FileInputStream(cellFile)) {
139 + return new Reservation(new String(ByteStreams.toByteArray(stream), "UTF-8"));
140 + } catch (IOException e) {
141 + throw new IllegalStateException("Unable to get current user for cell " + cellName, e);
142 + }
143 + }
144 +
145 + /**
146 + * Reserves a cell for the specified user and their public access key.
147 + *
148 + * @param userName user name
149 + * @param sshKey user ssh public key
150 + * @param minutes number of minutes for reservation
151 + * @return reserved cell definition
152 + */
153 + synchronized String borrowCell(String userName, String sshKey, int minutes) {
154 + checkNotNull(userName, USER_NOT_NULL);
155 + checkNotNull(sshKey, KEY_NOT_NULL);
156 + checkArgument(minutes > 0, "Number of minutes must be positive");
157 + checkArgument(minutes < MAX_MINUTES, "Number of minutes must be less than %d", MAX_MINUTES);
158 + long now = System.currentTimeMillis();
159 + Reservation reservation = currentUserReservation(userName);
160 + if (reservation == null) {
161 + Set<String> cells = getAvailableCells();
162 + checkState(!cells.isEmpty(), "No cells are presently available");
163 + String cellName = ImmutableList.copyOf(cells).get(random.nextInt(cells.size()));
164 + reservation = new Reservation(cellName, userName, now, minutes);
165 + } else {
166 + reservation = new Reservation(reservation.cellName, userName, now, minutes);
167 + }
168 +
169 + reserveCell(reservation.cellName, reservation);
170 + installUserKeys(reservation.cellName, userName, sshKey);
171 + log(userName, reservation.cellName, "borrowed for " + minutes + " minutes");
172 + return getCellDefinition(reservation.cellName);
173 + }
174 +
175 + /**
176 + * Reserves the specified cell for the user the source file and writes the
177 + * specified content to the target file.
178 + *
179 + * @param cellName cell name
180 + * @param reservation cell reservation record
181 + */
182 + private void reserveCell(String cellName, Reservation reservation) {
183 + try (FileOutputStream stream = new FileOutputStream(new File(reserved, cellName))) {
184 + stream.write(reservation.encode().getBytes(UTF_8));
185 + } catch (IOException e) {
186 + throw new IllegalStateException("Unable to reserve cell " + cellName, e);
187 + }
188 + }
189 +
190 + /**
191 + * Returns the specified cell for the specified user and their public access key.
192 + *
193 + * @param userName user name
194 + */
195 + synchronized void returnCell(String userName) {
196 + checkNotNull(userName, USER_NOT_NULL);
197 + Reservation reservation = currentUserReservation(userName);
198 + checkState(reservation != null, "User %s has no cell reservations", userName);
199 + checkState(new File(reserved, reservation.cellName).delete(),
200 + "Unable to return cell %s", reservation.cellName);
201 + uninstallUserKeys(reservation.cellName);
202 + log(userName, reservation.cellName, "returned");
203 + }
204 +
205 + /**
206 + * Reads the definition of the specified cell.
207 + *
208 + * @param cellName cell name
209 + * @return cell definition
210 + */
211 + String getCellDefinition(String cellName) {
212 + File cellFile = new File(supported, cellName);
213 + try (InputStream stream = new FileInputStream(cellFile)) {
214 + return new String(ByteStreams.toByteArray(stream), UTF_8);
215 + } catch (IOException e) {
216 + throw new IllegalStateException("Unable to definition for cell " + cellName, e);
217 + }
218 + }
219 +
220 + // Returns list of cell hosts, i.e. OC#, OCN
221 + private List<String> cellHosts(String cellName) {
222 + ImmutableList.Builder<String> builder = ImmutableList.builder();
223 + Pattern pattern = Pattern.compile("export OC[0-9N]=(.*)");
224 + for (String line : getCellDefinition(cellName).split("\n")) {
225 + Matcher matcher = pattern.matcher(line);
226 + if (matcher.matches()) {
227 + builder.add(matcher.group(1).replaceAll("[\"']", ""));
228 + }
229 + }
230 + return builder.build();
231 + }
232 +
233 + // Installs the specified user's key on all hosts of the given cell.
234 + private void installUserKeys(String cellName, String userName, String sshKey) {
235 + File authKeysFile = authKeys(sshKey);
236 + for (String host : cellHosts(cellName)) {
237 + installAuthorizedKey(host, authKeysFile.getPath());
238 + }
239 + checkState(authKeysFile.delete(), "Unable to install user keys");
240 + }
241 +
242 + // Uninstalls the user keys on the specified cell
243 + private void uninstallUserKeys(String cellName) {
244 + for (String host : cellHosts(cellName)) {
245 + installAuthorizedKey(host, AUTHORIZED_KEYS);
246 + }
247 + }
248 +
249 + // Installs the authorized keys on the specified host.
250 + private void installAuthorizedKey(String host, String authorizedKeysFile) {
251 + String cmd = "scp " + authorizedKeysFile + " sdn@" + host + ":.ssh/authorized_keys";
252 + try {
253 + Process process = Runtime.getRuntime().exec(cmd);
254 + process.waitFor(TIMEOUT, TimeUnit.SECONDS);
255 + } catch (Exception e) {
256 + throw new IllegalStateException("Unable to set authorized keys for host " + host);
257 + }
258 + }
259 +
260 + // Returns the file containing authorized keys that incudes the specified key.
261 + private File authKeys(String sshKey) {
262 + File keysFile = new File(AUTHORIZED_KEYS);
263 + try {
264 + File tmp = File.createTempFile("warden-", ".auth");
265 + tmp.deleteOnExit();
266 + try (InputStream stream = new FileInputStream(keysFile);
267 + PrintWriter output = new PrintWriter(tmp)) {
268 + String baseKeys = new String(ByteStreams.toByteArray(stream), UTF_8);
269 + output.println(baseKeys);
270 + output.println(sshKey);
271 + return tmp;
272 + } catch (IOException e) {
273 + throw new IllegalStateException("Unable to generate authorized keys", e);
274 + }
275 + } catch (IOException e) {
276 + throw new IllegalStateException("Unable to generate authorized keys", e);
277 + }
278 + }
279 +
280 + // Creates an audit log entry.
281 + void log(String userName, String cellName, String action) {
282 + try (FileOutputStream fos = new FileOutputStream(log, true);
283 + PrintWriter pw = new PrintWriter(fos)) {
284 + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
285 + pw.println(String.format("%s\t%s\t%s\t%s", format.format(new Date()),
286 + userName, cellName, action));
287 + pw.flush();
288 + } catch (IOException e) {
289 + throw new IllegalStateException("Unable to log reservation action", e);
290 + }
291 + }
292 +
293 + // Task for re-possessing overdue cells
294 + private class Reposessor extends TimerTask {
295 + @Override
296 + public void run() {
297 + long now = System.currentTimeMillis();
298 + for (String cellName : getReservedCells()) {
299 + Reservation reservation = currentCellReservation(cellName);
300 + if (reservation != null &&
301 + (reservation.time + reservation.duration * MINUTE) < now) {
302 + try {
303 + returnCell(reservation.userName);
304 + } catch (Exception e) {
305 + e.printStackTrace();
306 + }
307 + }
308 + }
309 + }
310 + }
311 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onlab.warden;
18 +
19 +import com.google.common.io.ByteStreams;
20 +import org.eclipse.jetty.server.Response;
21 +
22 +import javax.servlet.ServletException;
23 +import javax.servlet.http.HttpServlet;
24 +import javax.servlet.http.HttpServletRequest;
25 +import javax.servlet.http.HttpServletResponse;
26 +import java.io.IOException;
27 +import java.io.PrintWriter;
28 +import java.text.SimpleDateFormat;
29 +import java.util.Date;
30 +
31 +import static com.google.common.base.Strings.isNullOrEmpty;
32 +
33 +/**
34 + * Web socket servlet capable of creating web sockets for the STC monitor.
35 + */
36 +public class WardenServlet extends HttpServlet {
37 +
38 + static Warden warden;
39 +
40 + @Override
41 + protected void doGet(HttpServletRequest req, HttpServletResponse resp)
42 + throws ServletException, IOException {
43 + resp.setContentType("text/plain; charset=UTF-8");
44 + SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
45 +
46 + try (PrintWriter out = resp.getWriter()) {
47 + for (String cellName : warden.getCells()) {
48 + Reservation reservation = warden.currentCellReservation(cellName);
49 + if (reservation != null) {
50 + long expiration = reservation.time + reservation.duration * 60_000;
51 + out.println(String.format("%-10s\t%-10s\t%s\t%s\t%s minutes", cellName,
52 + reservation.userName,
53 + fmt.format(new Date(reservation.time)),
54 + fmt.format(new Date(expiration)),
55 + reservation.duration));
56 + } else {
57 + out.println(String.format("%-10s\t%-10s", cellName, "available"));
58 + }
59 + }
60 + } catch (Exception e) {
61 + resp.setStatus(Response.SC_INTERNAL_SERVER_ERROR);
62 + e.printStackTrace();
63 + }
64 + }
65 +
66 + @Override
67 + protected void doPost(HttpServletRequest req, HttpServletResponse resp)
68 + throws ServletException, IOException {
69 + try (PrintWriter out = resp.getWriter()) {
70 + String sshKey = new String(ByteStreams.toByteArray(req.getInputStream()), "UTF-8");
71 + String userName = req.getParameter("user");
72 + String sd = req.getParameter("duration");
73 + int duration = isNullOrEmpty(sd) ? 60 : Integer.parseInt(sd);
74 + String cellDefinition = warden.borrowCell(userName, sshKey, duration);
75 + out.println(cellDefinition);
76 + } catch (Exception e) {
77 + resp.setStatus(Response.SC_INTERNAL_SERVER_ERROR);
78 + e.printStackTrace();
79 + }
80 + }
81 +
82 + @Override
83 + protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
84 + throws ServletException, IOException {
85 + try (PrintWriter out = resp.getWriter()) {
86 + String userName = req.getParameter("user");
87 + warden.returnCell(userName);
88 + } catch (Exception e) {
89 + resp.setStatus(Response.SC_INTERNAL_SERVER_ERROR);
90 + e.printStackTrace();
91 + }
92 + }
93 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/**
18 + * Cell warden to coordinate borrowing and returning test cells.
19 + */
20 +package org.onlab.warden;
...\ No newline at end of file ...\ No newline at end of file