aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java
blob: 499436916134372e327b7dcc22f2a1d350cdbeab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * Copyright 2015 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onlab.stc;

import org.onlab.stc.Coordinator.Status;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;

import static java.lang.String.format;
import static org.onlab.stc.Coordinator.Status.FAILED;
import static org.onlab.stc.Coordinator.Status.SUCCEEDED;
import static org.onlab.stc.Coordinator.print;

/**
 * Manages execution of the specified step or a group.
 */
class StepProcessor implements Runnable {

    private static final String IGNORE_CODE = "~";
    private static final String NEGATE_CODE = "!";

    private static final int FAIL = -1;

    static String launcher = "stc-launcher ";

    private final Step step;
    private final File logDir;
    private String command;

    private Process process;
    private StepProcessListener delegate;

    /**
     * Creates a process monitor.
     *
     * @param step     step or group to be executed
     * @param logDir   directory where step process log should be stored
     * @param delegate process lifecycle listener
     * @param command  actual command to execute
     */
    StepProcessor(Step step, File logDir, StepProcessListener delegate,
                  String command) {
        this.step = step;
        this.logDir = logDir;
        this.delegate = delegate;
        this.command = command;
    }

    @Override
    public void run() {
        delegate.onStart(step, command);
        int code = execute();
        boolean ignoreCode = step.env() != null && step.env.equals(IGNORE_CODE);
        boolean negateCode = step.env() != null && step.env.equals(NEGATE_CODE);
        Status status = ignoreCode || code == 0 && !negateCode || code != 0 && negateCode ?
                SUCCEEDED : FAILED;
        delegate.onCompletion(step, status);
    }

    /**
     * Executes the step process.
     *
     * @return exit code
     */
    private int execute() {
        try (PrintWriter pw = new PrintWriter(logFile())) {
            process = Runtime.getRuntime().exec(command());
            processOutput(pw);

            // Wait for the process to complete and get its exit code.
            if (process.isAlive()) {
                process.waitFor();
            }
            return process.exitValue();

        } catch (IOException e) {
            print("Unable to run step %s using command %s", step.name(), step.command());
        } catch (InterruptedException e) {
            print("Step %s interrupted", step.name());
        }
        return FAIL;
    }

    /**
     * Returns ready-to-run command for the step.
     *
     * @return command to execute
     */
    private String command() {
        return format("%s %s %s %s", launcher,
                      step.env() != null ? step.env() : "-",
                      step.cwd() != null ? step.cwd() : "-",
                      command);
    }

    /**
     * Captures output of the step process.
     *
     * @param pw print writer to send output to
     * @throws IOException if unable to read output or write logs
     */
    private void processOutput(PrintWriter pw) throws IOException {
        InputStream out = process.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(out));

        // Slurp its combined stderr/stdout
        String line;
        while ((line = br.readLine()) != null) {
            pw.println(line);
            delegate.onOutput(step, line);
        }
    }

    /**
     * Returns the log file for the step output.
     *
     * @return log file
     */
    private File logFile() {
        return new File(logDir, step.name() + ".log");
    }

}