cycle) throws CycleDetectedException {
+ throw new CycleDetectedException(cycle);
+ }
+
+ public static final class CycleDetectedException extends Exception {
+ public final List cycle;
+
+ public CycleDetectedException(List cycle) {
+ super("Cycle detected: " + cycle.stream().map(Object::toString).collect(Collectors.joining(" -> ")));
+ this.cycle = cycle;
+ }
+ }
+}
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/process/EnvVars.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/EnvVars.java
new file mode 100644
index 0000000..20564be
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/EnvVars.java
@@ -0,0 +1,468 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package cd.casic.devops.common.process;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.UUID;
+import java.util.logging.Logger;
+
+// copy from jenkins 96a66619b55b3b78b86817798fe36e58b2798cd4
+
+/**
+ * Environment variables.
+ *
+ *
+ * While all the platforms I tested (Linux 2.6, Solaris, and Windows XP) have the case sensitive
+ * environment variable table, Windows batch script handles environment variable in the case preserving
+ * but case insensitive way (that is, cmd.exe can get both FOO and foo as environment variables
+ * when it's launched, and the "set" command will display it accordingly, but "echo %foo%" results in
+ * echoing the value of "FOO", not "foo" — this is presumably caused by the behavior of the underlying
+ * Win32 API {@code GetEnvironmentVariable} acting in case insensitive way.) Windows users are also
+ * used to write environment variable case-insensitively (like %Path% vs %PATH%), and you can see many
+ * documents on the web that claims Windows environment variables are case insensitive.
+ *
+ *
+ * So for a consistent cross platform behavior, it creates the least confusion to make the table
+ * case insensitive but case preserving.
+ *
+ *
+ * In Jenkins, often we need to build up "environment variable overrides"
+ * on the controller, then to execute the process on agents. This causes a problem
+ * when working with variables like {@code PATH}. So to make this work,
+ * we introduce a special convention {@code PATH+FOO} — all entries
+ * that starts with {@code PATH+} are merged and prepended to the inherited
+ * {@code PATH} variable, on the process where a new process is executed.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class EnvVars extends TreeMap {
+ private static final long serialVersionUID = 4320331661987259022L;
+ private static Logger LOGGER = Logger.getLogger(EnvVars.class.getName());
+ /**
+ * If this {@link EnvVars} object represents the whole environment variable set,
+ * not just a partial list used for overriding later, then we need to know
+ * the platform for which this env vars are targeted for, or else we won't know
+ * how to merge variables properly.
+ *
+ *
+ * So this property remembers that information.
+ */
+ private Platform platform;
+
+ /**
+ * Gets the platform for which these env vars targeted.
+ * @since 2.144
+ * @return The platform.
+ */
+ public Platform getPlatform() {
+ return platform;
+ }
+
+ /**
+ * Sets the platform for which these env vars target.
+ * @since 2.144
+ * @param platform the platform to set.
+ */
+ public void setPlatform(Platform platform) {
+ this.platform = platform;
+ }
+
+ public EnvVars() {
+ super(String.CASE_INSENSITIVE_ORDER);
+ }
+
+ public EnvVars(Map m) {
+ this();
+ putAll(m);
+
+ // because of the backward compatibility, some parts of Jenkins passes
+ // EnvVars as Map so downcasting is safer.
+ if (m instanceof EnvVars) {
+ EnvVars lhs = (EnvVars) m;
+ this.platform = lhs.platform;
+ }
+ }
+
+ @SuppressWarnings("CopyConstructorMissesField") // does not set #platform, see its Javadoc
+ public EnvVars(EnvVars m) {
+ // this constructor is so that in future we can get rid of the downcasting.
+ this((Map) m);
+ }
+
+ /**
+ * Builds an environment variables from an array of the form {@code "key","value","key","value"...}
+ */
+ public EnvVars(String... keyValuePairs) {
+ this();
+ if (keyValuePairs.length % 2 != 0)
+ throw new IllegalArgumentException(Arrays.asList(keyValuePairs).toString());
+ for (int i = 0; i < keyValuePairs.length; i += 2)
+ put(keyValuePairs[i], keyValuePairs[i + 1]);
+ }
+
+ /**
+ * Overrides the current entry by the given entry.
+ *
+ *
+ * Handles {@code PATH+XYZ} notation.
+ */
+ public void override(String key, String value) {
+ if (value == null || value.isEmpty()) {
+ remove(key);
+ return;
+ }
+
+ int idx = key.indexOf('+');
+ if (idx > 0) {
+ String realKey = key.substring(0, idx);
+ String v = get(realKey);
+ if (v == null) v = value;
+ else {
+ // we might be handling environment variables for a agent that can have different path separator
+ // than the controller, so the following is an attempt to get it right.
+ // it's still more error prone that I'd like.
+ char ch = platform == null ? File.pathSeparatorChar : platform.pathSeparator;
+ v = value + ch + v;
+ }
+ put(realKey, v);
+ return;
+ }
+
+ put(key, value);
+ }
+
+ /**
+ * Overrides all values in the map by the given map.
+ * See {@link #override(String, String)}.
+ * @return this
+ */
+ public EnvVars overrideAll(Map all) {
+ for (Map.Entry e : all.entrySet()) {
+ override(e.getKey(), e.getValue());
+ }
+ return this;
+ }
+
+ /**
+ * Calculates the order to override variables.
+ *
+ * Sort variables with topological sort with their reference graph.
+ *
+ * This is package accessible for testing purpose.
+ */
+ static class OverrideOrderCalculator {
+ /**
+ * Extract variables referred directly from a variable.
+ */
+ private static class TraceResolver implements VariableResolver {
+ private final Comparator super String> comparator;
+ public Set referredVariables;
+
+ TraceResolver(Comparator super String> comparator) {
+ this.comparator = comparator;
+ clear();
+ }
+
+ public void clear() {
+ referredVariables = new TreeSet<>(comparator);
+ }
+
+ @Override
+ public String resolve(String name) {
+ referredVariables.add(name);
+ return "";
+ }
+ }
+
+ private static class VariableReferenceSorter extends CyclicGraphDetector {
+ // map from a variable to a set of variables that variable refers.
+ private final Map> refereeSetMap;
+
+ VariableReferenceSorter(Map> refereeSetMap) {
+ this.refereeSetMap = refereeSetMap;
+ }
+
+ @Override
+ protected Iterable extends String> getEdges(String n) {
+ // return variables referred from the variable.
+ if (!refereeSetMap.containsKey(n)) {
+ // there is a case a non-existing variable is referred...
+ return Collections.emptySet();
+ }
+ return refereeSetMap.get(n);
+ }
+ }
+
+ private final Comparator super String> comparator;
+
+
+ private final EnvVars target;
+
+ private final Map overrides;
+
+ private Map> refereeSetMap;
+ private List orderedVariableNames;
+
+ OverrideOrderCalculator(EnvVars target, Map overrides) {
+ comparator = target.comparator();
+ this.target = target;
+ this.overrides = overrides;
+ scan();
+ }
+
+ public List getOrderedVariableNames() {
+ return orderedVariableNames;
+ }
+
+ // Cut the reference to the variable in a cycle.
+ private void cutCycleAt(String referee, List cycle) {
+ // cycle contains variables in referrer-to-referee order.
+ // This should not be negative, for the first and last one is same.
+ int refererIndex = cycle.lastIndexOf(referee) - 1;
+
+ assert refererIndex >= 0;
+ String referrer = cycle.get(refererIndex);
+ boolean removed = refereeSetMap.get(referrer).remove(referee);
+ assert removed;
+ LOGGER.warning(String.format("Cyclic reference detected: %s", String.join(" -> ", cycle)));
+ LOGGER.warning(String.format("Cut the reference %s -> %s", referrer, referee));
+ }
+
+ // Cut the variable reference in a cycle.
+ private void cutCycle(List cycle) {
+ // if an existing variable is contained in that cycle,
+ // cut the cycle with that variable:
+ // existing:
+ // PATH=/usr/bin
+ // overriding:
+ // PATH1=/usr/local/bin:${PATH}
+ // PATH=/opt/something/bin:${PATH1}
+ // then consider reference PATH1 -> PATH can be ignored.
+ for (String referee : cycle) {
+ if (target.containsKey(referee)) {
+ cutCycleAt(referee, cycle);
+ return;
+ }
+ }
+
+ // if not, cut the reference to the first one.
+ cutCycleAt(cycle.get(0), cycle);
+ }
+
+ /**
+ * Scan all variables and list all referring variables.
+ */
+ public void scan() {
+ refereeSetMap = new TreeMap<>(comparator);
+ List extendingVariableNames = new ArrayList<>();
+
+ TraceResolver resolver = new TraceResolver(comparator);
+
+ for (Map.Entry entry : overrides.entrySet()) {
+ if (entry.getKey().indexOf('+') > 0) {
+ // XYZ+AAA variables should be always processed in last.
+ extendingVariableNames.add(entry.getKey());
+ continue;
+ }
+ resolver.clear();
+ Util.replaceMacro(entry.getValue(), resolver);
+
+ // Variables directly referred from the current scanning variable.
+ Set refereeSet = resolver.referredVariables;
+ // Ignore self reference.
+ refereeSet.remove(entry.getKey());
+ refereeSetMap.put(entry.getKey(), refereeSet);
+ }
+
+ VariableReferenceSorter sorter;
+ while (true) {
+ sorter = new VariableReferenceSorter(refereeSetMap);
+ try {
+ sorter.run(refereeSetMap.keySet());
+ } catch (CyclicGraphDetector.CycleDetectedException e) {
+ // cyclic reference found.
+ // cut the cycle and retry.
+ @SuppressWarnings("unchecked")
+ List cycle = e.cycle;
+ cutCycle(cycle);
+ continue;
+ }
+ break;
+ }
+
+ // When A refers B, the last appearance of B always comes after
+ // the last appearance of A.
+ List reversedDuplicatedOrder = new ArrayList<>(sorter.getSorted());
+ Collections.reverse(reversedDuplicatedOrder);
+
+ orderedVariableNames = new ArrayList<>(overrides.size());
+ for (String key : reversedDuplicatedOrder) {
+ if (overrides.containsKey(key) && !orderedVariableNames.contains(key)) {
+ orderedVariableNames.add(key);
+ }
+ }
+ Collections.reverse(orderedVariableNames);
+ orderedVariableNames.addAll(extendingVariableNames);
+ }
+ }
+
+
+ /**
+ * Overrides all values in the map by the given map. Expressions in values will be expanded.
+ * See {@link #override(String, String)}.
+ * @return {@code this}
+ */
+ public EnvVars overrideExpandingAll(Map all) {
+ for (String key : new OverrideOrderCalculator(this, all).getOrderedVariableNames()) {
+ override(key, expand(all.get(key)));
+ }
+ return this;
+ }
+
+ /**
+ * Resolves environment variables against each other.
+ */
+ public static void resolve(Map env) {
+ for (Map.Entry entry : env.entrySet()) {
+ entry.setValue(Util.replaceMacro(entry.getValue(), env));
+ }
+ }
+
+ /**
+ * Convenience message
+ * @since 1.485
+ **/
+ public String get(String key, String defaultValue) {
+ String v = get(key);
+ if (v == null) v = defaultValue;
+ return v;
+ }
+
+ @Override
+ public String put(String key, String value) {
+ if (value == null) throw new IllegalArgumentException("Null value not allowed as an environment variable: " + key);
+ return super.put(key, value);
+ }
+
+ /**
+ * Add a key/value but only if the value is not-null. Otherwise no-op.
+ * @since 1.556
+ */
+ public void putIfNotNull(String key, String value) {
+ if (value != null)
+ put(key, value);
+ }
+
+ /**
+ * Add entire map but filter null values out.
+ * @since 2.214
+ */
+ public void putAllNonNull(Map map) {
+ map.forEach(this::putIfNotNull);
+ }
+
+
+ /**
+ * Takes a string that looks like "a=b" and adds that to this map.
+ */
+ public void addLine(String line) {
+ int sep = line.indexOf('=');
+ if (sep > 0) {
+ put(line.substring(0, sep), line.substring(sep + 1));
+ }
+ }
+
+ /**
+ * Expands the variables in the given string by using environment variables represented in 'this'.
+ */
+ public String expand(String s) {
+ return Util.replaceMacro(s, this);
+ }
+
+ /**
+ * Creates a magic cookie that can be used as the model environment variable
+ * when we later kill the processes.
+ */
+ public static EnvVars createCookie() {
+ return new EnvVars("HUDSON_COOKIE", UUID.randomUUID().toString());
+ }
+
+// /**
+// * Obtains the environment variables of a remote peer.
+// *
+// * @param channel
+// * Can be null, in which case the map indicating "N/A" will be returned.
+// * @return
+// * A fresh copy that can be owned and modified by the caller.
+// */
+// public static EnvVars getRemote(VirtualChannel channel) throws IOException, InterruptedException {
+// if (channel == null)
+// return new EnvVars("N/A", "N/A");
+// return channel.call(new GetEnvVars());
+// }
+//
+// private static final class GetEnvVars extends MasterToSlaveCallable {
+// @Override
+// public EnvVars call() {
+// return new EnvVars(EnvVars.masterEnvVars);
+// }
+//
+// private static final long serialVersionUID = 1L;
+// }
+//
+// /**
+// * Environmental variables that we've inherited.
+// *
+// *
+// * Despite what the name might imply, this is the environment variable
+// * of the current JVM process. And therefore, it is the Jenkins controller's
+// * environment variables only when you access this from the controller.
+// *
+// *
+// * If you access this field from agents, then this is the environment
+// * variable of the agent.
+// */
+// public static final Map masterEnvVars = initMaster();
+//
+// private static EnvVars initMaster() {
+// EnvVars vars = new EnvVars(System.getenv());
+// vars.platform = Platform.current();
+// if (Main.isUnitTest || Main.isDevelopmentMode)
+// // if unit test is launched with maven debug switch,
+// // we need to prevent forked Maven processes from seeing it, or else
+// // they'll hang
+// vars.remove("MAVEN_OPTS");
+// return vars;
+// }
+}
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/process/Platform.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/Platform.java
new file mode 100644
index 0000000..59021d2
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/Platform.java
@@ -0,0 +1,79 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package cd.casic.devops.common.process;
+
+
+import hudson.util.VersionNumber;
+
+import java.io.File;
+import java.util.Locale;
+
+// copy from jenkins 96a66619b55b3b78b86817798fe36e58b2798cd4
+
+/**
+ * Strategy object that absorbs the platform differences.
+ *
+ *
+ * Do not switch/case on this enum, or do a comparison, as we may add new constants.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public enum Platform {
+ WINDOWS(';'), UNIX(':');
+
+ /**
+ * The character that separates paths in environment variables like PATH and CLASSPATH.
+ * On Windows ';' and on Unix ':'.
+ *
+ * @see File#pathSeparator
+ */
+ public final char pathSeparator;
+
+ Platform(char pathSeparator) {
+ this.pathSeparator = pathSeparator;
+ }
+
+ public static Platform current() {
+ if (File.pathSeparatorChar == ':') return UNIX;
+ return WINDOWS;
+ }
+
+ public static boolean isDarwin() {
+ // according to http://developer.apple.com/technotes/tn2002/tn2110.html
+ return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("mac");
+ }
+
+ /**
+ * Returns true if we run on Mac OS X ≥ 10.6
+ */
+ public static boolean isSnowLeopardOrLater() {
+ try {
+ return isDarwin() && new VersionNumber(System.getProperty("os.version")).compareTo(new VersionNumber("10.6")) >= 0;
+ } catch (IllegalArgumentException e) {
+ // failed to parse the version
+ return false;
+ }
+ }
+}
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/process/ProcessKiller.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/ProcessKiller.java
new file mode 100644
index 0000000..25546ff
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/ProcessKiller.java
@@ -0,0 +1,48 @@
+/*
+ * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
+ *
+ * A copy of the MIT License is included in this file.
+ *
+ *
+ * Terms of the MIT License:
+ * ---------------------------------------------------
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+ * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package cd.casic.devops.common.process;
+
+import cd.casic.devops.common.process.BkProcessTree.OSProcess;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class ProcessKiller implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public ProcessKiller() {
+ }
+
+ public static List all() {
+ return new ArrayList<>();
+ }
+
+ public abstract boolean kill(OSProcess var1) throws IOException, InterruptedException;
+}
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/process/ProcessTreeRemoting.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/ProcessTreeRemoting.java
new file mode 100644
index 0000000..ca87988
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/ProcessTreeRemoting.java
@@ -0,0 +1,54 @@
+/*
+ * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
+ *
+ * A copy of the MIT License is included in this file.
+ *
+ *
+ * Terms of the MIT License:
+ * ---------------------------------------------------
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+ * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package cd.casic.devops.common.process;
+
+import java.util.List;
+import java.util.Map;
+
+public class ProcessTreeRemoting {
+ public ProcessTreeRemoting() {
+ }
+
+ public interface IOSProcess {
+ int getPid();
+
+ ProcessTreeRemoting.IOSProcess getParent();
+
+ void kill(boolean forceFlag) throws InterruptedException;
+
+ void killRecursively(boolean forceFlag) throws InterruptedException;
+
+ List getArguments();
+
+ EnvVars getEnvironmentVariables();
+ }
+
+ public interface IProcessTree {
+ void killAll(Map var1, boolean forceFlag) throws InterruptedException;
+ }
+}
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/process/QuotedStringTokenizer.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/QuotedStringTokenizer.java
new file mode 100644
index 0000000..281fc83
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/QuotedStringTokenizer.java
@@ -0,0 +1,557 @@
+/*
+ * (C) Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
+ *
+ * Parts of this code was taken from the Jetty project, which can be
+ * found at http://www.mortbay.org/jetty
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+// ========================================================================
+// Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// 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 cd.casic.devops.common.process;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+// copy from jenkins 96a66619b55b3b78b86817798fe36e58b2798cd4
+
+/* ------------------------------------------------------------ */
+
+/** StringTokenizer with Quoting support.
+ *
+ * This class is a copy of the java.util.StringTokenizer API and
+ * the behaviour is the same, except that single and double quoted
+ * string values are recognized.
+ * Delimiters within quotes are not considered delimiters.
+ * Quotes can be escaped with '\'.
+ *
+ * @see StringTokenizer
+ * @author Greg Wilkins (gregw)
+ */
+@SuppressWarnings("all")
+public class QuotedStringTokenizer
+ extends StringTokenizer
+{
+ private static final String __delim = " \t\n\r";
+ private String _string;
+ private String _delim = __delim;
+ private boolean _returnQuotes = false;
+ private boolean _returnDelimiters = false;
+ private StringBuilder _token;
+ private boolean _hasToken = false;
+ private int _i = 0;
+ private int _lastStart = 0;
+ private boolean _double = true;
+ private boolean _single = true;
+
+ public static String[] tokenize(String str) {
+ return new QuotedStringTokenizer(str).toArray();
+ }
+
+ public static String[] tokenize(String str, String delimiters) {
+ return new QuotedStringTokenizer(str, delimiters).toArray();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ *
+ * @param str
+ * String to tokenize.
+ * @param delim
+ * List of delimiter characters as string. Can be null, to default to ' \t\n\r'
+ * @param returnDelimiters
+ * If true, {@link #nextToken()} will include the delimiters, not just tokenized
+ * tokens.
+ * @param returnQuotes
+ * If true, {@link #nextToken()} will include the quotation characters when they are present.
+ */
+ public QuotedStringTokenizer(String str,
+ String delim,
+ boolean returnDelimiters,
+ boolean returnQuotes)
+ {
+ super("");
+ _string = str;
+ if (delim != null)
+ _delim = delim;
+ _returnDelimiters = returnDelimiters;
+ _returnQuotes = returnQuotes;
+
+ if (_delim.indexOf('\'') >= 0 ||
+ _delim.indexOf('"') >= 0)
+ throw new Error("Can't use quotes as delimiters: " + _delim);
+
+ _token = new StringBuilder(_string.length() > 1024 ? 512 : _string.length() / 2);
+ }
+
+ /* ------------------------------------------------------------ */
+ public QuotedStringTokenizer(String str,
+ String delim,
+ boolean returnDelimiters)
+ {
+ this(str, delim, returnDelimiters, false);
+ }
+
+ /* ------------------------------------------------------------ */
+ public QuotedStringTokenizer(String str,
+ String delim)
+ {
+ this(str, delim, false, false);
+ }
+
+ /* ------------------------------------------------------------ */
+ public QuotedStringTokenizer(String str)
+ {
+ this(str, null, false, false);
+ }
+
+ public String[] toArray() {
+ List r = new ArrayList<>();
+ while (hasMoreTokens())
+ r.add(nextToken());
+ return r.toArray(new String[r.size()]);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public boolean hasMoreTokens()
+ {
+ // Already found a token
+ if (_hasToken)
+ return true;
+
+ _lastStart = _i;
+
+ int state = 0;
+ boolean escape = false;
+ while (_i < _string.length())
+ {
+ char c = _string.charAt(_i++);
+
+ switch (state)
+ {
+ case 0: // Start
+ if (_delim.indexOf(c) >= 0)
+ {
+ if (_returnDelimiters)
+ {
+ _token.append(c);
+ return _hasToken = true;
+ }
+ }
+ else if (c == '\'' && _single)
+ {
+ if (_returnQuotes)
+ _token.append(c);
+ state = 2;
+ }
+ else if (c == '\"' && _double)
+ {
+ if (_returnQuotes)
+ _token.append(c);
+ state = 3;
+ }
+ else
+ {
+ _token.append(c);
+ _hasToken = true;
+ state = 1;
+ }
+ continue;
+
+ case 1: // Token
+ _hasToken = true;
+ if (escape)
+ {
+ escape = false;
+ if (ESCAPABLE_CHARS.indexOf(c) < 0)
+ _token.append('\\');
+ _token.append(c);
+ }
+ else if (_delim.indexOf(c) >= 0)
+ {
+ if (_returnDelimiters)
+ _i--;
+ return _hasToken;
+ }
+ else if (c == '\'' && _single)
+ {
+ if (_returnQuotes)
+ _token.append(c);
+ state = 2;
+ }
+ else if (c == '\"' && _double)
+ {
+ if (_returnQuotes)
+ _token.append(c);
+ state = 3;
+ }
+ else if (c == '\\')
+ {
+ escape = true;
+ }
+ else
+ _token.append(c);
+ continue;
+
+
+ case 2: // Single Quote
+ _hasToken = true;
+ if (escape)
+ {
+ escape = false;
+ if (ESCAPABLE_CHARS.indexOf(c) < 0)
+ _token.append('\\');
+ _token.append(c);
+ }
+ else if (c == '\'')
+ {
+ if (_returnQuotes)
+ _token.append(c);
+ state = 1;
+ }
+ else if (c == '\\')
+ {
+ if (_returnQuotes)
+ _token.append(c);
+ escape = true;
+ }
+ else
+ _token.append(c);
+ continue;
+
+
+ case 3: // Double Quote
+ _hasToken = true;
+ if (escape)
+ {
+ escape = false;
+ if (ESCAPABLE_CHARS.indexOf(c) < 0)
+ _token.append('\\');
+ _token.append(c);
+ }
+ else if (c == '\"')
+ {
+ if (_returnQuotes)
+ _token.append(c);
+ state = 1;
+ }
+ else if (c == '\\')
+ {
+ if (_returnQuotes)
+ _token.append(c);
+ escape = true;
+ }
+ else
+ _token.append(c);
+ continue;
+
+ default:
+ break;
+ }
+ }
+
+ return _hasToken;
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public String nextToken()
+ throws NoSuchElementException
+ {
+ if (!hasMoreTokens() || _token == null)
+ throw new NoSuchElementException();
+ String t = _token.toString();
+ _token.setLength(0);
+ _hasToken = false;
+ return t;
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public String nextToken(String delim)
+ throws NoSuchElementException
+ {
+ _delim = delim;
+ _i = _lastStart;
+ _token.setLength(0);
+ _hasToken = false;
+ return nextToken();
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public boolean hasMoreElements()
+ {
+ return hasMoreTokens();
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public Object nextElement()
+ throws NoSuchElementException
+ {
+ return nextToken();
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Not implemented.
+ */
+ @Override
+ public int countTokens()
+ {
+ return -1;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /** Quote a string.
+ * The string is quoted only if quoting is required due to
+ * embedded delimiters, quote characters or the
+ * empty string.
+ * @param s The string to quote.
+ * @return quoted string
+ */
+ public static String quote(String s, String delim)
+ {
+ if (s == null)
+ return null;
+ if (s.isEmpty())
+ return "\"\"";
+
+
+ for (int i = 0; i < s.length(); i++)
+ {
+ char c = s.charAt(i);
+ if (c == '\\' || c == '"' || c == '\'' || Character.isWhitespace(c) || delim.indexOf(c) >= 0)
+ {
+ StringBuffer b = new StringBuffer(s.length() + 8);
+ quote(b, s);
+ return b.toString();
+ }
+ }
+
+ return s;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Quote a string.
+ * The string is quoted only if quoting is required due to
+ * embedded delimiters, quote characters or the
+ * empty string.
+ * @param s The string to quote.
+ * @return quoted string
+ */
+ public static String quote(String s)
+ {
+ if (s == null)
+ return null;
+ if (s.isEmpty())
+ return "\"\"";
+
+ StringBuffer b = new StringBuffer(s.length() + 8);
+ quote(b, s);
+ return b.toString();
+
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /** Quote a string into a StringBuffer.
+ * The characters ", \, \n, \r, \t, \f and \b are escaped
+ * @param buf The StringBuffer
+ * @param s The String to quote.
+ */
+ public static void quote(StringBuffer buf, String s)
+ {
+ synchronized (buf)
+ {
+ buf.append('"');
+ for (int i = 0; i < s.length(); i++)
+ {
+ char c = s.charAt(i);
+ switch (c)
+ {
+ case '"':
+ buf.append("\\\"");
+ continue;
+ case '\\':
+ buf.append("\\\\");
+ continue;
+ case '\n':
+ buf.append("\\n");
+ continue;
+ case '\r':
+ buf.append("\\r");
+ continue;
+ case '\t':
+ buf.append("\\t");
+ continue;
+ case '\f':
+ buf.append("\\f");
+ continue;
+ case '\b':
+ buf.append("\\b");
+ continue;
+
+ default:
+ buf.append(c);
+ }
+ }
+ buf.append('"');
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Unquote a string.
+ * @param s The string to unquote.
+ * @return quoted string
+ */
+ public static String unquote(String s)
+ {
+ if (s == null)
+ return null;
+ if (s.length() < 2)
+ return s;
+
+ char first = s.charAt(0);
+ char last = s.charAt(s.length() - 1);
+ if (first != last || (first != '"' && first != '\''))
+ return s;
+
+ StringBuilder b = new StringBuilder(s.length() - 2);
+ boolean escape = false;
+ for (int i = 1; i < s.length() - 1; i++)
+ {
+ char c = s.charAt(i);
+
+ if (escape)
+ {
+ escape = false;
+ switch (c)
+ {
+ case 'n':
+ b.append('\n');
+ break;
+ case 'r':
+ b.append('\r');
+ break;
+ case 't':
+ b.append('\t');
+ break;
+ case 'f':
+ b.append('\f');
+ break;
+ case 'b':
+ b.append('\b');
+ break;
+ case 'u':
+ b.append((char) (
+ (convertHexDigit((byte) s.charAt(i++)) << 24) +
+ (convertHexDigit((byte) s.charAt(i++)) << 16) +
+ (convertHexDigit((byte) s.charAt(i++)) << 8) +
+ convertHexDigit((byte) s.charAt(i++))
+ )
+ );
+ break;
+ default:
+ b.append(c);
+ }
+ }
+ else if (c == '\\')
+ {
+ escape = true;
+ }
+ else
+ b.append(c);
+ }
+
+ return b.toString();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return handle double quotes if true
+ */
+ public boolean getDouble()
+ {
+ return _double;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param d handle double quotes if true
+ */
+ public void setDouble(boolean d)
+ {
+ _double = d;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return handle single quotes if true
+ */
+ public boolean getSingle()
+ {
+ return _single;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param single handle single quotes if true
+ */
+ public void setSingle(boolean single)
+ {
+ _single = single;
+ }
+
+ /**
+ * @param b An ASCII encoded character 0-9 a-f A-F
+ * @return The byte value of the character 0-16.
+ */
+ public static byte convertHexDigit(byte b)
+ {
+ if (b >= '0' && b <= '9') return (byte) (b - '0');
+ if (b >= 'a' && b <= 'f') return (byte) (b - 'a' + 10);
+ if (b >= 'A' && b <= 'F') return (byte) (b - 'A' + 10);
+ return 0;
+ }
+
+ /**
+ * Characters that can be escaped with \.
+ *
+ * Others, like, say, \W will be left alone instead of becoming just W.
+ * This is important to keep Hudson behave on Windows, which uses '\' as
+ * the directory separator.
+ */
+ private static final String ESCAPABLE_CHARS = "\\\"' ";
+}
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/process/Util.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/Util.java
new file mode 100644
index 0000000..626cf8f
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/Util.java
@@ -0,0 +1,101 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package cd.casic.devops.common.process;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+// copy from jenkins 96a66619b55b3b78b86817798fe36e58b2798cd4
+
+public class Util {
+ /**
+ * Convert null to "".
+ */
+ public static String fixNull(String s) {
+ return fixNull(s, "");
+ }
+
+ /**
+ * Convert {@code null} to a default value.
+ *
+ * @param defaultValue Default value. It may be immutable or not, depending on the implementation.
+ * @since 2.144
+ */
+ public static T fixNull(T s, T defaultValue) {
+ return s != null ? s : defaultValue;
+ }
+
+ /**
+ * Pattern for capturing variables. Either $xyz, ${xyz} or ${a.b} but not $a.b, while ignoring "$$"
+ */
+ private static final Pattern VARIABLE = Pattern.compile("\\$([A-Za-z0-9_]+|\\{[A-Za-z0-9_.]+\\}|\\$)");
+
+ /**
+ * Replaces the occurrence of '$key' by {@code properties.get('key')}.
+ *
+ *
+ * Unlike shell, undefined variables are left as-is (this behavior is the same as Ant.)
+ */
+ public static String replaceMacro(String s, Map properties) {
+ return replaceMacro(s, new VariableResolver.ByMap<>(properties));
+ }
+
+ /**
+ * Replaces the occurrence of '$key' by {@code resolver.get('key')}.
+ *
+ *
+ * Unlike shell, undefined variables are left as-is (this behavior is the same as Ant.)
+ */
+ public static String replaceMacro(String s, VariableResolver resolver) {
+ if (s == null) {
+ return null;
+ }
+
+ int idx = 0;
+ while (true) {
+ Matcher m = VARIABLE.matcher(s);
+ if (!m.find(idx)) return s;
+
+ String key = m.group().substring(1);
+
+ // escape the dollar sign or get the key to resolve
+ String value;
+ if (key.charAt(0) == '$') {
+ value = "$";
+ } else {
+ if (key.charAt(0) == '{') key = key.substring(1, key.length() - 1);
+ value = resolver.resolve(key);
+ }
+
+ if (value == null)
+ idx = m.end(); // skip this
+ else {
+ s = s.substring(0, m.start()) + value + s.substring(m.end());
+ idx = m.start() + value.length();
+ }
+ }
+ }
+}
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/process/VariableResolver.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/VariableResolver.java
new file mode 100644
index 0000000..3cfee78
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/VariableResolver.java
@@ -0,0 +1,102 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package cd.casic.devops.common.process;
+
+import java.util.Collection;
+import java.util.Map;
+
+// copy from jenkins 96a66619b55b3b78b86817798fe36e58b2798cd4
+
+/**
+ * Resolves variables to its value, while encapsulating
+ * how that resolution happens.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public interface VariableResolver {
+ /**
+ * Receives a variable name and obtains the value associated with the name.
+ *
+ *
+ * This can be implemented simply on top of a {@link Map} (see {@link ByMap}), or
+ * this can be used like an expression evaluator.
+ *
+ * @param name
+ * Name of the variable to be resolved.
+ * Never null, never empty. The name shouldn't include the syntactic
+ * marker of an expression. IOW, it should be "foo" but not "${foo}".
+ * A part of the goal of this design is to abstract away the expression
+ * marker syntax.
+ * @return
+ * Object referenced by the name.
+ * Null if not found.
+ */
+ V resolve(String name);
+
+ /**
+ * Empty resolver that always returns null.
+ */
+ VariableResolver NONE = name -> null;
+
+ /**
+ * {@link VariableResolver} backed by a {@link Map}.
+ */
+ final class ByMap implements VariableResolver {
+ private final Map data;
+
+ public ByMap(Map data) {
+ this.data = data;
+ }
+
+ @Override
+ public V resolve(String name) {
+ return data.get(name);
+ }
+ }
+
+ /**
+ * Union of multiple {@link VariableResolver}.
+ */
+ final class Union implements VariableResolver {
+ private final VariableResolver extends V>[] resolvers;
+
+ public Union(VariableResolver extends V>... resolvers) {
+ this.resolvers = resolvers.clone();
+ }
+
+ public Union(Collection extends VariableResolver extends V>> resolvers) {
+ this.resolvers = resolvers.toArray(new VariableResolver[0]);
+ }
+
+ @Override
+ public V resolve(String name) {
+ for (VariableResolver extends V> r : resolvers) {
+ V v = r.resolve(name);
+ if (v != null) return v;
+ }
+ return null;
+ }
+ }
+}
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/process/jna/GNUCLibrary.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/jna/GNUCLibrary.java
new file mode 100644
index 0000000..bfb155a
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/process/jna/GNUCLibrary.java
@@ -0,0 +1,148 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package cd.casic.devops.common.process.jna;
+
+import com.sun.jna.LastErrorException;
+import com.sun.jna.Library;
+import com.sun.jna.Memory;
+import com.sun.jna.Native;
+import com.sun.jna.NativeLong;
+import com.sun.jna.Pointer;
+import com.sun.jna.StringArray;
+import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.NativeLongByReference;
+
+// copy from jenkins 96a66619b55b3b78b86817798fe36e58b2798cd4
+
+/**
+ * GNU C library.
+ *
+ *
+ * Not available on all platforms (such as Linux/PPC, IBM mainframe, etc.), so the caller should recover gracefully
+ * in case of {@link LinkageError}. See JENKINS-4820.
+ * @author Kohsuke Kawaguchi
+ */
+public interface GNUCLibrary extends Library {
+ int fork();
+
+ int kill(int pid, int signum);
+
+ int setsid();
+
+ int umask(int mask);
+
+ int getpid();
+
+ int geteuid();
+
+ int getegid();
+
+ int getppid();
+
+ int chdir(String dir);
+
+ int getdtablesize();
+
+ int execv(String path, StringArray args);
+
+ int execvp(String file, StringArray args);
+
+ int setenv(String name, String value, int replace);
+
+ int unsetenv(String name);
+
+ void perror(String msg);
+
+ String strerror(int errno);
+
+ int fcntl(int fd, int command);
+
+ int fcntl(int fd, int command, Object... flags);
+
+ // obtained from Linux. Needs to be checked if these values are portable.
+ int F_GETFD = 1;
+ int F_SETFD = 2;
+ int FD_CLOEXEC = 1;
+
+ int chown(String fileName, int uid, int gid);
+
+ int chmod(String fileName, int i);
+
+ int open(String pathname, int flags) throws LastErrorException;
+
+ int dup(int old);
+
+ int dup2(int old, int _new);
+
+ long pread(int fd, Memory buffer, NativeLong size, NativeLong offset) throws LastErrorException;
+
+ int close(int fd);
+
+ // see http://www.gnu.org/s/libc/manual/html_node/Renaming-Files.html
+ int rename(String oldname, String newname);
+
+ // The following three functions are Darwin-specific. The native "long" and "size_t" types always have
+ // the same size on Darwin, we use NativeLong and NativeLongByReference where the native functions use
+ // "size_t" and "size_t *" respectively. By updating JNA to 5.9.0 and adding a dependency on "jna-platform",
+ // the "com.sun.jna.platform.unix.LibCAPI.size_t" and "com.sun.jna.platform.unix.LIBCAPI.size_t.ByReference"
+ // types could be used instead.
+
+ // this is listed in http://developer.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man3/sysctlbyname.3.html
+ // but not in http://www.gnu.org/software/libc/manual/html_node/System-Parameters.html#index-sysctl-3493
+ // perhaps it is only supported on BSD?
+ @Deprecated
+ int sysctlbyname(String name, Pointer oldp, IntByReference oldlenp, Pointer newp, IntByReference newlen);
+
+ int sysctlbyname(String name, Pointer oldp, NativeLongByReference oldlenp, Pointer newp, NativeLong newlen);
+
+ @Deprecated
+ int sysctl(int[] mib, int nameLen, Pointer oldp, IntByReference oldlenp, Pointer newp, IntByReference newlen);
+
+ int sysctl(int[] name, int namelen, Pointer oldp, NativeLongByReference oldlenp, Pointer newp, NativeLong newlen);
+
+ @Deprecated
+ int sysctlnametomib(String name, Pointer mibp, IntByReference size);
+
+ int sysctlnametomib(String name, Pointer mibp, NativeLongByReference sizep);
+
+ /**
+ * Creates a symlink.
+ *
+ * See symlink(3)
+ */
+ int symlink(String oldname, String newname);
+
+ /**
+ * Read a symlink. The name will be copied into the specified memory, and returns the number of
+ * bytes copied. The string is not null-terminated.
+ *
+ * @return
+ * if the return value equals size, the caller needs to retry with a bigger buffer.
+ * If -1, error.
+ */
+ int readlink(String filename, Memory buffer, NativeLong size);
+
+ GNUCLibrary LIBC = Native.load("c", GNUCLibrary.class);
+}
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/Constants.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/Constants.java
new file mode 100644
index 0000000..1b8fdff
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/Constants.java
@@ -0,0 +1,34 @@
+package cd.casic.devops.common.worker;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Constants {
+ public static final String BUILD_ID = "devops.build.id";
+ public static final String BUILD_TYPE = "build.type";
+ public static final String WORKSPACE_ENV = "WORKSPACE";
+ public static final String COMMON_ENV_CONTEXT = "common_env";
+ public static final String WORKSPACE_CONTEXT = "ci.workspace";
+ public static final String CI_TOKEN_CONTEXT = "ci.token";
+ public static final String JOB_OS_CONTEXT = "job.os";
+ public static final String SLAVE_AGENT_START_FILE = "devops.slave.agent.start.file";
+ public static final String SLAVE_AGENT_PREPARE_START_FILE = "devops.slave.agent.prepare.start.file";
+ public static final String AGENT_ERROR_MSG_FILE = "devops.agent.error.file";
+ public static final String CLEAN_WORKSPACE = "DEVOPS_CLEAN_WORKSPACE";
+ public static final String JAVA_PATH_ENV = "bk_java_path";
+ public static final String NODEJS_PATH_ENV = "bk_nodejs_path";
+ public static final String LOG_DEBUG_FLAG = "##[debug]";
+ public static final String LOG_ERROR_FLAG = "##[error]";
+ public static final String LOG_WARN_FLAG = "##[warning]";
+ public static final String LOG_SUBTAG_FLAG = "##subTag##";
+ public static final String LOG_SUBTAG_FINISH_FLAG = "##subTagFinish##";
+ public static final int LOG_MESSAGE_LENGTH_LIMIT = 16 * 1024; // 16KB
+ public static final int LOG_TASK_LINE_LIMIT = 1000000;
+ public static final long LOG_FILE_LENGTH_LIMIT = 1073741824L; // 1 GB = 1073741824 Byte
+ public static final List PIPELINE_SCRIPT_ATOM_CODE = Arrays.asList(
+ "PipelineScriptDev",
+ "PipelineScriptTest",
+ "PipelineScript"
+ );
+ public static final String BK_CI_ATOM_EXECUTE_ENV_PATH = "BK_CI_ATOM_EXECUTE_ENV_PATH";
+}
\ No newline at end of file
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/constant/WorkerMessageCode.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/constant/WorkerMessageCode.java
new file mode 100644
index 0000000..003e300
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/constant/WorkerMessageCode.java
@@ -0,0 +1,230 @@
+/*
+ * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
+ *
+ * A copy of the MIT License is included in this file.
+ *
+ * ...
+ */
+
+package cd.casic.devops.common.worker.constant;
+
+public class WorkerMessageCode {
+ public static final String MSG_CODE_ROLE_PREFIX = "MSG_CODE_ROLE_PREFIX_";// 角色国际化前缀
+ public static final String MSG_CODE_PERMISSION_PREFIX = "MSG_CODE_PERMISSION_PREFIX_";// 操作权限国际化前缀
+ public static final String SUCCESS = "0";// 成功
+ public static final int OAUTH_DENERD = 418;// 自定义状态码, 未进行oauth认证
+ public static final String SYSTEM_ERROR = "2100001";// 系统内部繁忙,请稍后再试
+ public static final String PARAMETER_IS_NULL = "2100002";// 参数{0}不能为空
+ public static final String PARAMETER_IS_EXIST = "2100003";// 参数值{0}已经存在系统,请换一个再试
+ public static final String PARAMETER_IS_INVALID = "2100004";// 参数值{0}为非法数据
+ public static final String OAUTH_TOKEN_IS_INVALID = "2100005";// 无效的token,请先oauth认证
+ public static final String PERMISSION_DENIED = "2100006";// 无权限{0}
+ public static final String ERROR_SERVICE_NO_FOUND = "2100007";// "找不到任何有效的{0}服务提供者"
+ public static final String ERROR_SERVICE_INVOKE_FAILURE = "2100008";// "服务调用失败:{0},uniqueId={1}"
+ public static final String ERROR_INVALID_CONFIG = "2100009";// "配置不可用:{0},uniqueId={1}"
+ public static final String ERROR_REST_EXCEPTION_COMMON_TIP = "2100010";// 接口访问出现异常,请联系助手或稍后再重试
+ public static final String ERROR_CLIENT_REST_ERROR = "2100011";// 用户请求不合法,参数或方法错误,请咨询助手
+ public static final String ERROR_PROJECT_FEATURE_NOT_ACTIVED = "2100012";// 项目[{0}]未开通该功能
+ public static final String ERROR_INVALID_PARAM_ = "2100013";// 无效参数: {0}
+ public static final String ERROR_NEED_PARAM_ = "2100014";// 缺少参数: {0}
+ public static final String PARAMETER_VALIDATE_ERROR = "2100015";// {0}参数校验错误: {1}
+ public static final String ERROR_SERVICE_NO_AUTH = "2100016";// 无访问服务的权限
+ public static final String ERROR_QUERY_NUM_TOO_BIG = "2100017";// 查询的数量超过系统规定的值:{0},请调整查询条件或咨询助手
+ public static final String ERROR_QUERY_TIME_RANGE_TOO_LARGE = "2100018";// 查询的时间范围跨度最大,最长时间范围跨度不能超过{0}天
+ public static final String ERROR_HTTP_RESPONSE_BODY_TOO_LARGE = "2100019";// http请求返回体太大
+ public static final String PERMISSION_DENIED_FOR_APP = "2100020";// APP的无权限{0}
+ public static final String ERROR_SENSITIVE_API_NO_AUTH = "2100021";// 无敏感API访问权限
+ public static final String PARAMETER_LENGTH_TOO_LONG = "2100022";// 参数长度不能超过{0}个字符
+ public static final String PARAMETER_LENGTH_TOO_SHORT = "2100023";// 参数长度不能小于{0}个字符
+ public static final String PARAMETER_ILLEGAL_ERROR = "2100024";// {0}参数非法错误: {1}
+ public static final String PARAMETER_EXPIRED_ERROR = "2100025";// {0}token过期错误: {1}
+ public static final String PARAMETER_SECRET_ERROR = "2100026";// {0}密钥配置错误: {1}
+ public static final String PARAMETER_IS_EMPTY = "2100027";// 参数不能为空
+ public static final String ERROR_QUERY_TIME_RANGE_ERROR = "2100028";// 查询的时间范围跨度错误
+ public static final String SERVICE_NOT_EXIST = "2100029";// 父服务不存在异常
+
+ public static final String ILLEGAL_GITCI_SERVICE_IMAGE_FORMAT = "2100030";// GITCI Service镜像格式非法
+ public static final String THIRD_PARTY_SERVICE_DEVCLOUD_EXCEPTION = "2100031";// 第三方服务-DEVCLOUD 异常,请联系8006排查,异常信息 -
+ public static final String CREATE_CONTAINER_INTERFACE_EXCEPTION = "2100032";// 创建容器接口异常
+ public static final String CREATE_CONTAINER_RETURNS_FAILED = "2100033";// 创建容器接口返回失败
+ public static final String CREATE_CONTAINER_TIMED_OUT = "2100034";// 创建容器接口超时
+ public static final String OPERATION_CONTAINER_INTERFACE_EXCEPTION = "2100035";// 操作容器接口异常
+ public static final String OPERATION_CONTAINER_RETURNED_FAILURE = "2100036";// 操作容器接口返回失败
+ public static final String OPERATION_CONTAINER_TIMED_OUT = "2100037";// 操作容器接口超时
+ public static final String GET_STATUS_INTERFACE_EXCEPTION = "2100038";// 获取容器状态接口异常
+ public static final String GET_STATUS_TIMED_OUT = "2100039";// 获取容器状态接口超时
+ public static final String CREATE_MIRROR_INTERFACE_EXCEPTION = "2100040";// 创建镜像接口异常
+ public static final String CREATE_MIRROR_INTERFACE_RETURNED_FAILURE = "2100041";// 创建镜像接口返回失败
+ public static final String CREATE_MIRROR_INTERFACE_EXCEPTION_NEW = "2100042";// 创建镜像新版本接口异常
+ public static final String NEW_MIRROR_INTERFACE_RETURNED_FAILURE = "2100043";// 创建镜像新版本接口返回失败
+ public static final String TASK_STATUS_INTERFACE_EXCEPTION = "2100044";// 获取TASK状态接口异常
+ public static final String TASK_STATUS_TIMED_OUT = "2100045";// 获取TASK状态接口超时
+ public static final String GET_WEBSOCKET_INTERFACE_EXCEPTION = "2100046";// 获取websocket接口异常
+ public static final String PARAMETER_CANNOT_EMPTY_ALL = "2100047";// 参数不能全部为空
+ public static final String USERS_EXCEEDS_THE_LIMIT = "2100048";// 授权用户数越界:{0}
+ public static final String FAILED_TO_QUERY_GSE_AGENT_STATUS = "2100049";// 查询 Gse Agent 状态失败
+ public static final String FAILED_TO_GET_AGENT_STATUS = "2100050";// 获取agent状态失败
+ public static final String STAGES_AND_STEPS_CANNOT_EXIST_BY_SIDE = "2100053";// stages和steps不能并列存在!
+
+ public static final String USER_NOT_PERMISSIONS_OPERATE_PIPELINE = "2100054";// 用户({0})无权限在工程({1})下{2}流水线{3}
+ public static final String USER_NOT_HAVE_PROJECT_PERMISSIONS = "2100055";// 用户 {0}无项目{1}权限
+ public static final String UNABLE_GET_PIPELINE_JOB_STATUS = "2100056";// 无法获取流水线JOB状态,构建停止
+ public static final String JOB_BUILD_STOPS = "2100057";// 流水线JOB已经不再运行,构建停止
+ public static final String PIPELINE_NAME_OCCUPIED = "2100058";// 流水线名称已被他人使用
+ public static final String INTERNAL_DEPENDENCY_SERVICE_EXCEPTION = "2100059";// 内部依赖服务异常
+ public static final String PUBLIC_BUILD_RESOURCE_POOL_NOT_EXIST = "2100060";// 公共构建资源池不存在,请检查yml配置.
+ public static final String ERROR_LANGUAGE_IS_NOT_SUPPORT = "2100061";// 该语言蓝盾目前不支持,蓝盾目前支持的语言标识为:{0}
+ public static final String INIT_SERVICE_LIST_ERROR = "2100062";// 初始化服务列表异常问题
+ public static final String FILE_NOT_EXIST = "2100063";// 文件{0}不存在
+ public static final String USER_ACCESS_CHECK_FAIL = "2100064";// Gitlab access token 不正确
+
+ public static final String GITLAB_TOKEN_EMPTY = "2100065";// GitLab Token为空
+ public static final String GITLAB_HOOK_URL_EMPTY = "2100066";// GitLab hook url为空
+ public static final String GITLAB_TOKEN_FAIL = "2100067";// GitLab Token不正确
+ public static final String GIT_TOKEN_FAIL = "2100068";// Git Token不正确
+ public static final String SERCRT_EMPTY = "2100069";// GIT 私钥为空
+ public static final String GIT_SERCRT_WRONG = "2100070";// Git 私钥不对
+ public static final String PWD_EMPTY = "2100071";// 用户密码为空
+ public static final String USER_NAME_EMPTY = "2100072";// 用户名为空
+ public static final String GITLAB_INVALID = "2100073";// 无效的GITLAB仓库
+ public static final String GIT_TOKEN_WRONG = "2100074";// Git Token 不正确
+ public static final String GIT_LOGIN_FAIL = "2100075";// Git 用户名或者密码不对
+ public static final String GIT_TOKEN_EMPTY = "2100076";// Git Token为空
+ public static final String GIT_HOOK_URL_EMPTY = "2100077";// Git hook url为空
+ public static final String TGIT_LOGIN_FAIL = "2100078";// TGit 用户名或者密码不对
+ public static final String TGIT_TOKEN_FAIL = "2100079";// TGit Token 不正确
+ public static final String TGIT_SECRET_WRONG = "2100080";// TGit 私钥不对
+ public static final String SVN_SECRET_OR_PATH_ERROR = "2100081";// SVN 私钥不正确 或者 SVN 路径没有权限
+ public static final String SVN_CREATE_HOOK_FAIL = "2100082";// 添加SVN WEB hook 失败
+ public static final String LOCK_FAIL = "2100083";// lock失败
+ public static final String UNLOCK_FAIL = "2100084";// unlock失败
+ public static final String GIT_REPO_PEM_FAIL = "2100085";// 代码仓库访问未授权
+ public static final String CALL_REPO_ERROR = "2100086";// 代码仓库访问异常
+ public static final String P4_USERNAME_PASSWORD_FAIL = "2100087";// p4用户名密码错误
+ public static final String PARAM_ERROR = "2100088";// 参数错误
+ public static final String AUTH_FAIL = "2100089";// {0}认证失败
+ public static final String ACCOUNT_NO_OPERATION_PERMISSIONS = "2100090";// 账户没有{0}的权限
+ public static final String REPO_NOT_EXIST_OR_NO_OPERATION_PERMISSION = "2100091";// {0}仓库不存在或者是账户没有该项目{1}的权限
+ public static final String GIT_INTERFACE_NOT_EXIST = "2100092";// {0}平台没有{1}的接口
+ public static final String GIT_CANNOT_OPERATION = "2100093";// {0}平台{1}操作不能进行
+ public static final String WEBHOOK_LOCK_UNLOCK_FAIL = "2100094";// unlock webhooklock失败,请确认token是否已经配置
+ public static final String COMMIT_CHECK_ADD_FAIL = "2100095";// Commit Check添加失败,请确保该代码库的凭据关联的用户对代码库有Developer权限
+ public static final String ADD_MR_COMMENTS_FAIL = "2100096";// 添加MR的评论失败,请确保该代码库的凭据关联的用户对代码库有Developer权限
+ public static final String WEBHOOK_ADD_FAIL = "2100097";// Webhook添加失败,请确保该代码库的凭据关联的用户对代码库有{0}权限
+ public static final String WEBHOOK_UPDATE_FAIL = "2100098";// Webhook更新失败,请确保该代码库的凭据关联的用户对代码库有Developer权限
+ public static final String ENGINEERING_REPO_UNAUTHORIZED = "2100099";// 工程仓库访问未授权
+ public static final String ENGINEERING_REPO_NOT_EXIST = "2100100";// 工程仓库不存在
+ public static final String ENGINEERING_REPO_CALL_ERROR = "2100101";// 工程仓库访问异常
+ public static final String NOT_MEMBER_AND_NOT_OPEN_SOURCE = "2100102";// 非项目成员且项目为非开源项目
+ public static final String USER_NO_PIPELINE_PERMISSION = "2100108";// 流水线: 用户无{0}权限
+ public static final String SERVICE_COULD_NOT_BE_ANALYZED = "2100109";// 无法根据接口"{0}"分析所属的服务
+ public static final String RETURNED_RESULT_COULD_NOT_BE_PARSED = "2100110";// 内部服务返回结果无法解析 status:{0} body:{1}
+ public static final String SERVICE_PROVIDER_NOT_FOUND = "2100111";// 找不到任何有效的{0}【{1}】服务提供者
+ public static final String ILLEGAL_JOB_TYPE = "2100112";// 非法的job类型!
+ public static final String ERROR_YAML_FORMAT_EXCEPTION = "2100113";// {0} 中 {1} 格式有误,应为 {2}, error message:{3}
+ public static final String ERROR_YAML_FORMAT_EXCEPTION_CHECK_STAGE_LABEL = "2100114";// 请核对Stage标签是否正确
+ public static final String ERROR_YAML_FORMAT_EXCEPTION_LENGTH_LIMIT_EXCEEDED = "2100115";// "{0} job.id 超过长度限制64 {1}}"
+ public static final String ERROR_YAML_FORMAT_EXCEPTION_NEED_PARAM = "2100116";// {0} 中的step必须包含uses或run或checkout!
+ public static final String ERROR_YAML_FORMAT_EXCEPTION_SERVICE_IMAGE_FORMAT_ILLEGAL = "2100117";// STREAM Service镜像格式非法
+ public static final String ERROR_YAML_FORMAT_EXCEPTION_STEP_ID_UNIQUENESS = "2100118";// 请确保step.id唯一性!({0})
+ public static final String BUILD_RESOURCE_NOT_EXIST = "2100119";// {0}构建资源不存在,请检查yml配置.
+ public static final String ERROR_YAML_FORMAT_EXCEPTION_ENV_QUANTITY_LIMIT_EXCEEDED = "2100120";// {0}配置Env数量超过100限制!
+ ;// {0}Env单变量{1}长度超过{2}字符!({3})
+ public static final String ERROR_YAML_FORMAT_EXCEPTION_ENV_VARIABLE_LENGTH_LIMIT_EXCEEDED = "2100121";
+ public static final String ERROR_PROJECT_API_ACCESS_NO_PERMISSION = "2100122";// 项目[{0}]没有接口[{1}]的访问权限
+ public static final String ERROR_INTERFACE_RETRY_NUM_EXCEEDED = "2100123";// 接口连续重试次数超过{0}次,请稍后再试
+ public static final String ERROR_PIPELINE_API_ACCESS_NO_PERMISSION = "2100124";// 流水线[{0}]没有接口[{1}]的访问权限
+ public static final String TEMPLATE_PLUGIN_NOT_ALLOWED_USE = "2100125";// 模板中插件【{0}】的【{1}】版本的状态是【{2}】,不允许使用
+ public static final String ADD_MR_FAIL = "2100126";// 添加MR失败
+
+ ;// 互转使用
+ public static final String ELEMENT_UPDATE_WRONG_PATH = "2100127";// 更新插件的标注位置有误
+ public static final String ELEMENT_NOT_SUPPORT_TRANSFER = "2100128";// 如下插件在 Code 方式下已不支持,请修改后再切换: \n[{0}]
+ public static final String DISPATCH_NOT_SUPPORT_TRANSFER = "2100129";// 如下构建环境在 Code 方式下不支持转换,请修改后再切换: \n[{0}]
+ public static final String YAML_NOT_VALID = "2100130";// yaml不合法 {0}
+ public static final String GIT_INVALID_PRIVATE_KEY = "2100131";// 不支持的SSH私钥格式,仅支持rsa格式私钥
+ public static final String GIT_INVALID_PRIVATE_KEY_OR_PASSWORD = "2100132";// 第三方服务[{0}]操作失败,失败详情:{1}
+ public static final String MR_ACCEPT_EVENT_NOT_SUPPORT_TRANSFER = "2100133";// mr accept事件类型不支持code转换
+
+ public static final String SVN_TOKEN_FAIL = "2100135";// SVN Token 不正确
+ public static final String SVN_TOKEN_EMPTY = "2100136";// SVN Token 为空, 请检查代码库的凭证类型
+ public static final String BK_CONTAINER_TIMED_OUT = "bkContainerTimedOut";// 创建容器超时
+ public static final String BK_CREATION_FAILED_EXCEPTION_INFORMATION = "bkCreationFailedExceptionInformation";// 创建失败,异常信息
+
+ public static final String BK_FILE_NAME = "bkFileName";// 文件名
+ public static final String BK_BELONG_TO_THE_PROJECT = "bkBelongToTheProject";// 所属项目
+ public static final String BK_OPERATING = "bkOperating";// 操作
+ public static final String BK_PUSH_FROM_BLUE_SHIELD_DEVOPS_PLATFORM = "bkPushFromBlueShieldDevopsPlatform";// 来自蓝盾DevOps平台的推送
+ public static final String BK_TABLE_CONTENTS = "bkTableContents";// 表格内容
+ public static final String BK_PLEASE_FEEL_TO_CONTACT_BLUE_SHIELD_ASSISTANT = "bkPleaseFeelToContactBlueShieldAssistant";// 如有任何问题,可随时联系蓝盾助手
+ public static final String BK_ETH1_NETWORK_CARD_IP_EMPTY = "bkEth1NetworkCardIpEmpty";// eth1 网卡Ip为空,因此,获取eth0的网卡ip
+ public static final String BK_LOOPBACK_ADDRESS_OR_NIC_EMPTY = "bkLoopbackAddressOrNicEmpty";// loopback地址或网卡名称为空
+ public static final String BK_FAILED_GET_NETWORK_CARD = "bkFailedGetNetworkCard";// 获取网卡失败
+ public static final String BK_MANUAL_TRIGGER = "bkManualTrigger";// 手动触发
+ public static final String BK_BUILD_TRIGGER = "bkBuildTrigger";// 构建触发
+ public static final String BK_VIEW_DETAILS = "bkSeeDetails";// 查看详情
+ public static final String BK_PROJECT_ID = "bkProjectId";// # 项目ID:
+ public static final String BK_PIPELINE_NAME = "bkPipelineName";// # 流水线名称:
+ public static final String BK_CREATE_SERVICE = "bkCreateService";// 创建{0}服务
+ public static final String BK_SESSION_ID = "bkSessionId";// 会话ID
+ public static final String BK_GROUP_ID = "bkGroupId";// 群ID
+ public static final String BK_THIS_GROUP_ID = "bkThisGroupId";// 本群ID={0}。PS:群ID可用于蓝盾平台上任意企业微信群通知。
+ public static final String BK_MISSING_RESOURCE_DEPENDENCY = "bkMissingResourceDependency";// 依赖的资源不存在
+
+ public static final String BK_REQUEST_TIMED_OUT = "bkRequestTimedOut";// 请求超时
+ public static final String BK_QUERY_PARAM_REQUEST_ERROR = "bkQueryParamRequestError";// 查询参数请求错误
+ public static final String BK_JSON_BAD_PARAMETERS = "bkJsonBadParameters";// JSON参数错误/Bad Parameters in json
+ ;// 请求体内容参数错误。温馨提示:请确认{0}是否符合要求
+ public static final String BK_REQUEST_BODY_CONTENT_PARAMETER_INCORRECT = "bkRequestBodyContentParameterIncorrect";
+ public static final String BK_REQUESTED_RESOURCE_DOES_NOT_EXIST = "bkRequestedResourceDoesNotExist";// 请求的资源不存在
+ public static final String BK_NOT_OAUTH_CERTIFICATION = "bkNotOauthCertification";// 你没有Oauth认证
+ public static final String BK_QUERY_PARAM_REQUEST_EMPTY = "bkQueryParamRequestEmpty";// 请求的参数内容为空
+ public static final String BK_QUERY_PARAM_TYPE_ERROR = "bkQueryParamTypeError";// 查询参数类型错误
+ ;// 你没有权限进行该操作
+ public static final String BK_NOT_HAVE_PERMISSION_PERFORM_THIS_OPERATION = "bkNotHavePermissionPerformThisOperation";// 访问后台数据失败,已通知产品、开发,请稍后重试
+ public static final String BK_FAILED_ACCESS_BACKGROUND_DATA = "bkFailedAccessBackgroundData";// 未授权访问的资源
+ public static final String BK_RESOURCES_THAT_NOT_AUTHORIZED_ACCESS = "bkResourcesThatNotAuthorizedAccess";
+ public static final String BK_CODE_BASE_TRIGGERING = "bkCodeBaseTriggering";// 代码库触发
+ public static final String BK_FAILED_START_BUILD_MACHINE = "bkFailedStartBuildMachine";// 启动构建机失败
+
+ public static final String CREATE_BRANCH = "bkCreateBranch";// 创建分支
+ public static final String DELETE_BRANCH = "bkDeleteBranch";// 删除分支
+
+ public static final String GET_PROJECT_INFO = "bkGetProjectInfo";// 获取项目详情
+ public static final String GET_COMMIT_REVIEW_INFO = "bkGetCommitReviewInfo";// 获取Commit Review详情
+ public static final String GET_SESSION_INFO = "bkGetSessionInfo";// 获取会话详情
+
+ public static final String OPERATION_BRANCH = "bkOperationBranch";// 拉分支
+ public static final String OPERATION_TAG = "bkOperationTag";// 拉标签
+ public static final String OPERATION_ADD_WEBHOOK = "bkOperationAddWebhook";// 添加WEBHOOK
+ public static final String OPERATION_UPDATE_WEBHOOK = "bkOperationUpdateWebhook";// 修改WEBHOOK
+ public static final String OPERATION_LIST_WEBHOOK = "bkOperationListWebhook";// 查询WEBHOOK
+ public static final String OPERATION_ADD_COMMIT_CHECK = "bkOperationAddCommitCheck";// 添加COMMIT CHECK
+ public static final String OPERATION_ADD_MR_COMMENT = "bkOperationAddMrComment";// 添加MR COMMENT
+ public static final String OPERATION_LIST_MR = "bkOperationListMr";// 添加MR
+ public static final String OPERATION_ADD_MR = "bkOperationAddMr";// 添加MR
+ public static final String OPERATION_COMMIT = "bkOperationCommit";// 拉提交记录
+ public static final String OPERATION_COMMIT_DIFF = "bkOperationCommitDiff";// 查询commit变化
+ public static final String OPERATION_UNLOCK_HOOK_LOCK = "bkOperationUnlockHookLock";// 解锁hook锁
+ public static final String OPERATION_MR_CHANGE = "bkOperationMrChange";// 查询合并请求的代码变更
+ public static final String OPERATION_MR_INFO = "bkOperationMrInfo";// 查询项目合并请求
+ public static final String OPERATION_GET_CHANGE_FILE_LIST = "bkOperationGetChangeFileList";// 查询变更文件列表
+ public static final String OPERATION_GET_MR_COMMIT_LIST = "bkOperationGetMrCommitList";// 获取合并请求中的提交
+ public static final String OPERATION_PROJECT_USER_INFO = "bkOperationProjectUserInfo";// 获取项目中成员信息
+ public static final String OPERATION_TAPD_WORKITEMS = "bkOperationTapdWorkItems";// 查看绑定的TAPD单
+ public static final String BK_USER_GROUP_CRATE_TIME = "bkUserGroupCrateTime";// {0} 用户组:{1},由{2} 创建于
+ public static final String BK_USER_RATING_ADMIN_CRATE_TIME = "bkUserRatingAdminCrateTime";// {0} 分级管理员,由{1} 创建于
+ public static final String BK_SECOND_LEVEL_ADMIN_CREATE = "bkSecondLevelAdminCreate";// {0} 二级管理员, 由{1} 创建于
+ public static final String BK_SECOND_LEVEL_ADMIN_REVISE = "bkSecondLevelAdminRevise";// {0} 二级管理员, 由{1} 修改于
+ ;// 用户 {0} 申请{1}蓝盾项目 {2} ,请审批!
+ public static final String BK_USER_REQUESTS_THE_PROJECT = "bkUserRequestsTheProject";
+ public static final String BK_ENV_NOT_YET_SUPPORTED = "bkEnvNotYetSupported";// 尚未支持 {0} {1},请联系 管理员 添加对应版本
+
+ public static final String BK_BUILD_ENV_TYPE = "BUILD_ENV_TYPE_";// 构建环境-
+ public static final String BK_BUILD_ENV_TYPE_BUILDLESS = "BUILD_ENV_TYPE_BUILDLESS";// 无编译环境
+ public static final String BK_BUILD_ENV_TYPE_BUILD_TRIGGERS = "BUILD_ENV_TYPE_BUILD_TRIGGER";// 构建触发
+}
\ No newline at end of file
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/AgentEnv.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/AgentEnv.java
new file mode 100644
index 0000000..728e06b
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/AgentEnv.java
@@ -0,0 +1,186 @@
+/*
+ * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
+ *
+ * A copy of the MIT License is included in this file.
+ *
+ * ...
+ */
+
+package cd.casic.devops.common.worker.env;
+
+import lombok.SneakyThrows;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sun.awt.OSInfo;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Locale;
+import java.util.Properties;
+
+public class AgentEnv {
+ private static final Logger logger = LoggerFactory.getLogger(AgentEnv.class);
+
+ public static final String PROJECT_ID = "devops.project.id";
+ public static final String DOCKER_PROJECT_ID = "devops_project_id";
+ public static final String AGENT_ID = "devops.agent.id";
+ public static final String DOCKER_AGENT_ID = "devops_agent_id";
+ public static final String AGENT_SECRET_KEY = "devops.agent.secret.key";
+ public static final String DOCKER_AGENT_SECRET_KEY = "devops_agent_secret_key";
+ public static final String AGENT_GATEWAY = "landun.gateway";
+ public static final String DOCKER_GATEWAY = "devops_gateway";
+ public static final String AGENT_FILE_GATEWAY = "DEVOPS_FILE_GATEWAY";
+ public static final String AGENT_ENV = "landun.env";
+ public static final String AGENT_LOG_SAVE_MODE = "devops_log_save_mode";
+ public static final String AGENT_PROPERTIES_FILE_NAME = ".agent.properties";
+ public static final String BK_TAG = "devops_bk_tag";
+ public static final String PUBLIC_HOST_MAX_FILE_CACHE_SIZE = "devops.public.host.maxFileCacheSize";
+ public static final String THIRD_HOST_MAX_FILE_CACHE_SIZE = "devops.public.third.maxFileCacheSize";
+
+ private static String projectId;
+ private static String agentId;
+ private static String secretKey;
+ private static String gateway;
+ private static String fileGateway;
+ private static OSInfo.OSType os;
+// private static Env env;
+// private static LogStorageMode logStorageMode;
+ private static String bkTag;
+ private static Properties property;
+
+ private static final File propertyFile = new File(System.getProperty("user.home"), AGENT_PROPERTIES_FILE_NAME);
+
+ public static String getProjectId() {
+ if (projectId == null) {
+ synchronized (AgentEnv.class) {
+ if (projectId == null) {
+ projectId = getProperty(PROJECT_ID);
+ logger.info("Get the project ID({})", projectId);
+ }
+ }
+ }
+ return projectId;
+ }
+
+ public static String getAgentId() {
+ if (agentId == null) {
+ synchronized (AgentEnv.class) {
+ if (agentId == null) {
+ agentId = getProperty(AGENT_ID);
+ logger.info("Get the agent ID({})", agentId);
+ }
+ }
+ }
+ return agentId;
+ }
+
+ public static String getSecretKey() {
+ if (secretKey == null) {
+ synchronized (AgentEnv.class) {
+ if (secretKey == null) {
+ secretKey = getProperty(AGENT_SECRET_KEY);
+ logger.info("Get the secret key({})", secretKey);
+ }
+ }
+ }
+ return secretKey;
+ }
+
+ public static String getGateway() {
+ if (gateway == null) {
+ synchronized (AgentEnv.class) {
+ if (gateway == null) {
+ gateway = getProperty(AGENT_GATEWAY);
+ logger.info("Get the gateway({})", gateway);
+ }
+ }
+ }
+ return gateway;
+ }
+
+ public static String getFileGateway() {
+ if (fileGateway == null) {
+ synchronized (AgentEnv.class) {
+ if (fileGateway == null) {
+ fileGateway = getProperty(AGENT_FILE_GATEWAY);
+ logger.info("Get the file gateway({})", fileGateway);
+ }
+ }
+ }
+ return fileGateway;
+ }
+
+ public static OSInfo.OSType getOs() {
+ if (os == null) {
+ synchronized (AgentEnv.class) {
+ if (os == null) {
+ os = OSInfo.OSType.valueOf(System.getProperty("os.name").toUpperCase(Locale.ROOT));
+ logger.info("Get the OS type({})", os);
+ }
+ }
+ }
+ return os;
+ }
+
+ /* public static LogStorageMode getLogMode() {
+ if (logStorageMode == null) {
+ synchronized (AgentEnv.class) {
+ if (logStorageMode == null) {
+ logStorageMode = LogStorageMode.valueOf(getProperty(AGENT_LOG_SAVE_MODE));
+ logger.info("Get the log mode({})", logStorageMode);
+ }
+ }
+ }
+ return logStorageMode;
+ }*/
+
+ public static String getBkTag() {
+ if (bkTag == null) {
+ synchronized (AgentEnv.class) {
+ if (bkTag == null) {
+ bkTag = getProperty(BK_TAG);
+ logger.info("Get the bkTag({})", bkTag);
+ }
+ }
+ }
+ return bkTag;
+ }
+
+ @SneakyThrows
+ public static String getProperty(String prop) {
+ if (property == null) {
+ if (!propertyFile.exists()) {
+ throw new Exception("The property file(" + propertyFile.getAbsolutePath() + ") does not exist");
+// throw new ParamBlankException("The property file(" + propertyFile.getAbsolutePath() + ") does not exist");
+ }
+ property = new Properties();
+ try (FileInputStream fis = new FileInputStream(propertyFile)) {
+ property.load(fis);
+ } catch (Exception e) {
+ logger.error("Failed to load properties from file", e);
+ }
+ }
+ return property.getProperty(prop);
+ }
+
+ public static String getEnvProp(String prop) {
+ String value = System.getenv(prop);
+ if (value == null || value.isEmpty()) {
+ value = System.getProperty(prop);
+ }
+ return value;
+ }
+
+ public static boolean isDockerEnv() {
+ return BuildEnv.getBuildType() == BuildType.DOCKER;
+ }
+
+ public static String getLocaleLanguage() {
+ return null;
+// return System.getProperty(LOCALE_LANGUAGE, System.getenv(LOCALE_LANGUAGE) != null ? System.getenv(LOCALE_LANGUAGE) : DEFAULT_LOCALE_LANGUAGE);
+ }
+}
\ No newline at end of file
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/BuildEnv.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/BuildEnv.java
new file mode 100644
index 0000000..f59788a
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/BuildEnv.java
@@ -0,0 +1,51 @@
+/*
+ * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
+ *
+ * A copy of the MIT License is included in this file.
+ *
+ * ...
+ */
+
+package cd.casic.devops.common.worker.env;
+
+
+import static cd.casic.devops.common.worker.Constants.BUILD_ID;
+import static cd.casic.devops.common.worker.Constants.BUILD_TYPE;
+
+public class BuildEnv {
+ private static String buildType;
+
+ public static BuildType getBuildType() {
+ if (buildType == null) {
+ synchronized (BuildEnv.class) {
+ if (buildType == null) {
+ buildType = System.getProperty(BUILD_TYPE);
+ }
+ }
+ }
+ if (buildType == null || !BuildType.contains(buildType)) {
+ return BuildType.AGENT;
+ }
+ return BuildType.valueOf(buildType);
+ }
+
+ public static void setBuildType(BuildType value) {
+ buildType = value.name();
+ }
+
+ public static boolean isThirdParty() {
+ return getBuildType() == BuildType.AGENT;
+ }
+
+ public static String getBuildId() {
+ return System.getProperty(BUILD_ID);
+ }
+
+ public static void setBuildId(String buildId) {
+ System.setProperty(BUILD_ID, buildId);
+ }
+}
\ No newline at end of file
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/BuildType.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/BuildType.java
new file mode 100644
index 0000000..2ec1f7c
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/BuildType.java
@@ -0,0 +1,30 @@
+/*
+ * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
+ *
+ * A copy of the MIT License is included in this file.
+ *
+ * ...
+ */
+
+package cd.casic.devops.common.worker.env;
+
+public enum BuildType {
+ WORKER,
+ AGENT,
+ MACOS,
+ MACOS_NEW,
+ DOCKER;
+
+ public static boolean contains(String env) {
+ for (BuildType type : values()) {
+ if (type.name().equals(env)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/DockerEnv.java b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/DockerEnv.java
new file mode 100644
index 0000000..1291609
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/env/DockerEnv.java
@@ -0,0 +1,198 @@
+/*
+ * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
+ *
+ * A copy of the MIT License is included in this file.
+ *
+ * ...
+ */
+
+package cd.casic.devops.common.worker.env;
+
+import com.tencent.devops.worker.common.exception.PropertyNotExistException;
+import lombok.SneakyThrows;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DockerEnv {
+ private static final Logger logger = LoggerFactory.getLogger(DockerEnv.class);
+
+ private static final String PROJECT_ID = "devops_project_id";
+ private static final String BUILD_ID = "devops_build_id";
+ private static final String AGENT_ID = "devops_agent_id";
+ private static final String AGENT_SECRET_KEY = "devops_agent_secret_key";
+ private static final String AGENT_GATEWAY = "devops_gateway";
+ private static final String JOB_POOL = "JOB_POOL";
+ private static final String DOCKER_HOST_IP = "docker_host_ip";
+ private static final String DOCKER_HOST_PORT = "docker_host_port";
+ private static final String HOSTNAME = "HOSTNAME";
+
+ private static String projectId;
+ private static String buildId;
+ private static String agentId;
+ private static String secretKey;
+ private static String gateway;
+ private static String jobPool;
+ private static String dockerHostIp;
+ private static String dockerHostPort;
+ private static String hostname;
+
+ public static void setProjectId(String projectId) {
+ System.setProperty(PROJECT_ID, projectId);
+ }
+
+ @SneakyThrows
+ public static String getProjectId() {
+ if (projectId == null) {
+ synchronized (DockerEnv.class) {
+ if (projectId == null) {
+ projectId = getProperty(PROJECT_ID);
+ if (projectId == null || projectId.isEmpty()) {
+ throw new Exception(PROJECT_ID+ "Empty project Id");
+// throw new PropertyNotExistException(PROJECT_ID, "Empty project Id");
+ }
+ logger.info("Get the project ID({})", projectId);
+ }
+ }
+ }
+ return projectId;
+ }
+
+ public static void setBuildId(String buildId) {
+ System.setProperty(BUILD_ID, buildId);
+ }
+
+ @SneakyThrows
+ public static String getBuildId() {
+ if (buildId == null) {
+ synchronized (DockerEnv.class) {
+ if (buildId == null) {
+ buildId = getProperty(BUILD_ID);
+ if (buildId == null || buildId.isEmpty()) {
+ throw new Exception(BUILD_ID+ "Empty build Id");
+// throw new PropertyNotExistException(BUILD_ID, "Empty build Id");
+ }
+ logger.info("Get the build ID({})", buildId);
+ }
+ }
+ }
+ return buildId;
+ }
+
+ public static String getAgentId() {
+ if (agentId == null) {
+ synchronized (DockerEnv.class) {
+ if (agentId == null) {
+ agentId = getProperty(AGENT_ID);
+ if (agentId == null || agentId.isEmpty()) {
+ throw new PropertyNotExistException(AGENT_ID, "Empty agent Id");
+ }
+ logger.info("Get the agent ID({})", agentId);
+ }
+ }
+ }
+ return agentId;
+ }
+
+ public static void setAgentSecretKey(String secretKey) {
+ System.setProperty(AGENT_SECRET_KEY, secretKey);
+ }
+
+ public static String getAgentSecretKey() {
+ if (secretKey == null) {
+ synchronized (DockerEnv.class) {
+ if (secretKey == null) {
+ secretKey = getProperty(AGENT_SECRET_KEY);
+ if (secretKey == null || secretKey.isEmpty()) {
+ throw new PropertyNotExistException(AGENT_SECRET_KEY, "Empty agent secret key");
+ }
+ logger.info("Get the agent secret key({})", secretKey);
+ }
+ }
+ }
+ return secretKey;
+ }
+
+ public static String getGateway() {
+ if (gateway == null) {
+ synchronized (DockerEnv.class) {
+ if (gateway == null) {
+ gateway = getProperty(AGENT_GATEWAY);
+ if (gateway == null || gateway.isEmpty()) {
+ throw new PropertyNotExistException(AGENT_GATEWAY, "Empty agent gateway");
+ }
+ logger.info("Get the gateway({})", gateway);
+ }
+ }
+ }
+ return gateway;
+ }
+
+ public static String getJobPool() {
+ if (jobPool == null) {
+ synchronized (DockerEnv.class) {
+ if (jobPool == null) {
+ jobPool = getProperty(JOB_POOL);
+ logger.info("Get the jobPool({})", jobPool);
+ }
+ }
+ }
+ return jobPool;
+ }
+
+ public static String getDockerHostIp() {
+ if (dockerHostIp == null) {
+ synchronized (DockerEnv.class) {
+ if (dockerHostIp == null) {
+ dockerHostIp = getProperty(DOCKER_HOST_IP);
+ if (dockerHostIp == null || dockerHostIp.isEmpty()) {
+ throw new PropertyNotExistException(DOCKER_HOST_IP, "Empty dockerHostIp");
+ }
+ logger.info("Get the dockerHostIp({})", dockerHostIp);
+ }
+ }
+ }
+ return dockerHostIp;
+ }
+
+ public static String getDockerHostPort() {
+ if (dockerHostPort == null) {
+ synchronized (DockerEnv.class) {
+ if (dockerHostPort == null) {
+ dockerHostPort = getProperty(DOCKER_HOST_PORT);
+ if (dockerHostPort == null || dockerHostPort.isEmpty()) {
+ throw new PropertyNotExistException(DOCKER_HOST_PORT, "Empty dockerHostPort");
+ }
+ logger.info("Get the dockerHostPort({})", dockerHostPort);
+ }
+ }
+ }
+ return dockerHostPort;
+ }
+
+ public static String getHostname() {
+ if (hostname == null) {
+ synchronized (DockerEnv.class) {
+ if (hostname == null) {
+ hostname = getProperty(HOSTNAME);
+ if (hostname == null || hostname.isEmpty()) {
+ throw new PropertyNotExistException(HOSTNAME, "Empty hostname");
+ }
+ logger.info("Get the hostname({})", hostname);
+ }
+ }
+ }
+ return hostname;
+ }
+
+ private static String getProperty(String prop) {
+ String value = System.getenv(prop);
+ if (value == null || value.isEmpty()) {
+ value = System.getProperty(prop);
+ }
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/exception/TaskExecuteExceptionDecorator.kt b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/exception/TaskExecuteExceptionDecorator.kt
new file mode 100644
index 0000000..172de70
--- /dev/null
+++ b/modules/ci-worker/src/main/java/cd/casic/devops/common/worker/exception/TaskExecuteExceptionDecorator.kt
@@ -0,0 +1,154 @@
+//package com.tencent.devops.worker.common.exception
+//
+//import com.fasterxml.jackson.databind.exc.InvalidFormatException
+//import com.fasterxml.jackson.databind.exc.MismatchedInputException
+//import com.tencent.devops.common.api.exception.RemoteServiceException
+//import com.tencent.devops.common.api.exception.TaskExecuteException
+//import com.tencent.devops.common.api.pojo.ErrorCode
+//import com.tencent.devops.common.api.pojo.ErrorType
+//import com.tencent.devops.worker.common.exception.TaskExecuteExceptionDecorator.LOGGER
+//import org.slf4j.Logger
+//import org.slf4j.LoggerFactory
+//import java.io.FileNotFoundException
+//import java.io.IOException
+//
+///**
+// * 错误处理
+// */
+//object TaskExecuteExceptionDecorator {
+//
+// val LOGGER: Logger = LoggerFactory.getLogger(TaskExecuteExceptionDecorator::class.java)
+//
+// private val defaultExceptionBase = DefaultExceptionBase()
+//
+// private val factory = mutableMapOf(
+// IllegalStateException::class to IllegalStateExceptionD(),
+// InvalidFormatException::class to InvalidFormatExceptionD(),
+// FileNotFoundException::class to FileNotFoundExceptionD(),
+// RemoteServiceException::class to RemoteServiceExceptionD(),
+// MismatchedInputException::class to MismatchedInputExceptionD(),
+// IOException::class to IOExceptionD(),
+// FileSystemException::class to FileSystemExceptionD()
+// )
+//
+// @Suppress("UNCHECKED_CAST")
+// fun decorate(throwable: Throwable): TaskExecuteException {
+// var exception = throwable
+// return (factory[exception::class] as ExceptionDecorator? ?: exception.cause?.let { cause ->
+// (factory[cause::class] as ExceptionDecorator?)?.let {
+// exception = cause
+// it
+// }
+// } ?: defaultExceptionBase).decorate(exception)
+// }
+//}
+//
+//class DefaultExceptionBase : ExceptionDecorator {
+// override fun decorate(exception: Throwable): TaskExecuteException {
+// return when {
+// exception is TaskExecuteException -> exception
+// // TEE只有一层,所以不遍历cause,防止InputMismatchException 无限循环。
+// exception.cause is TaskExecuteException -> exception.cause as TaskExecuteException
+// else -> {
+// LOGGER.warn("[Worker Error]: ", exception)
+// val defaultMessage = StringBuilder("Unknown system error has occurred with StackTrace:\n")
+// defaultMessage.append(exception.toString())
+// exception.stackTrace.forEach {
+// with(it) {
+// defaultMessage.append(
+// "\n at $className.$methodName($fileName:$lineNumber)"
+// )
+// }
+// }
+// TaskExecuteException(
+// errorMsg = exception.message ?: defaultMessage.toString(),
+// errorType = ErrorType.SYSTEM,
+// errorCode = ErrorCode.SYSTEM_WORKER_LOADING_ERROR,
+// cause = exception
+// )
+// }
+// }
+// }
+//}
+//
+//interface ExceptionDecorator {
+// fun decorate(exception: T): TaskExecuteException
+//}
+//
+//class IllegalStateExceptionD : ExceptionDecorator {
+// override fun decorate(exception: IllegalStateException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "Machine process error: ${exception.message}",
+// errorType = ErrorType.USER,
+// errorCode = ErrorCode.THIRD_PARTY_BUILD_ENV_ERROR,
+// cause = exception
+// )
+// }
+//}
+//
+//class FileNotFoundExceptionD : ExceptionDecorator {
+// override fun decorate(exception: FileNotFoundException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "Machine file not found error: ${exception.message}",
+// errorType = ErrorType.USER,
+// errorCode = ErrorCode.USER_RESOURCE_NOT_FOUND,
+// cause = exception
+// )
+// }
+//}
+//
+//class RemoteServiceExceptionD : ExceptionDecorator {
+//
+// override fun decorate(exception: RemoteServiceException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "THIRD PARTY response error: ${exception.message}",
+// errorType = ErrorType.THIRD_PARTY,
+// errorCode = ErrorCode.THIRD_PARTY_INTERFACE_ERROR,
+// cause = exception
+// )
+// }
+//}
+//
+//class MismatchedInputExceptionD : ExceptionDecorator {
+// override fun decorate(exception: MismatchedInputException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "Plugin data is illegal: ${exception.message}",
+// errorType = ErrorType.PLUGIN,
+// errorCode = ErrorCode.USER_TASK_OPERATE_FAIL,
+// cause = exception
+// )
+// }
+//}
+//
+//class InvalidFormatExceptionD : ExceptionDecorator {
+// override fun decorate(exception: InvalidFormatException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "Plugin data is illegal: ${exception.message}",
+// errorType = ErrorType.PLUGIN,
+// errorCode = ErrorCode.USER_TASK_OPERATE_FAIL,
+// cause = exception
+// )
+// }
+//}
+//
+//class IOExceptionD : ExceptionDecorator {
+// override fun decorate(exception: IOException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "IO Exception: ${exception.message}",
+// errorType = ErrorType.USER,
+// errorCode = ErrorCode.USER_RESOURCE_NOT_FOUND,
+// cause = exception
+// )
+// }
+//}
+//
+//class FileSystemExceptionD : ExceptionDecorator {
+// override fun decorate(exception: FileSystemException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "FileSystem Exception: ${exception.message}",
+// errorType = ErrorType.USER,
+// errorCode = ErrorCode.USER_RESOURCE_NOT_FOUND,
+// cause = exception
+// )
+// }
+//}
diff --git a/modules/ci-worker/src/main/kotlin/cd.casic.devops.common.worker.exception/ApiNotExistException.kt b/modules/ci-worker/src/main/kotlin/cd.casic.devops.common.worker.exception/ApiNotExistException.kt
new file mode 100644
index 0000000..4f0f2c2
--- /dev/null
+++ b/modules/ci-worker/src/main/kotlin/cd.casic.devops.common.worker.exception/ApiNotExistException.kt
@@ -0,0 +1,30 @@
+/*
+ * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
+ *
+ * A copy of the MIT License is included in this file.
+ *
+ *
+ * Terms of the MIT License:
+ * ---------------------------------------------------
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+ * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package com.tencent.devops.worker.common.exception
+
+class ApiNotExistException(message: String) : RuntimeException(message)
diff --git a/modules/ci-worker/src/main/kotlin/cd.casic.devops.common.worker.exception/PropertyNotExistException.kt b/modules/ci-worker/src/main/kotlin/cd.casic.devops.common.worker.exception/PropertyNotExistException.kt
new file mode 100644
index 0000000..0683b4f
--- /dev/null
+++ b/modules/ci-worker/src/main/kotlin/cd.casic.devops.common.worker.exception/PropertyNotExistException.kt
@@ -0,0 +1,30 @@
+/*
+ * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
+ *
+ * A copy of the MIT License is included in this file.
+ *
+ *
+ * Terms of the MIT License:
+ * ---------------------------------------------------
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+ * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package com.tencent.devops.worker.common.exception
+
+class PropertyNotExistException(val key: String, message: String) : RuntimeException(message)
diff --git a/modules/ci-worker/src/main/kotlin/cd.casic.devops.common.worker.exception/TaskExecuteExceptionDecorator.kt b/modules/ci-worker/src/main/kotlin/cd.casic.devops.common.worker.exception/TaskExecuteExceptionDecorator.kt
new file mode 100644
index 0000000..172de70
--- /dev/null
+++ b/modules/ci-worker/src/main/kotlin/cd.casic.devops.common.worker.exception/TaskExecuteExceptionDecorator.kt
@@ -0,0 +1,154 @@
+//package com.tencent.devops.worker.common.exception
+//
+//import com.fasterxml.jackson.databind.exc.InvalidFormatException
+//import com.fasterxml.jackson.databind.exc.MismatchedInputException
+//import com.tencent.devops.common.api.exception.RemoteServiceException
+//import com.tencent.devops.common.api.exception.TaskExecuteException
+//import com.tencent.devops.common.api.pojo.ErrorCode
+//import com.tencent.devops.common.api.pojo.ErrorType
+//import com.tencent.devops.worker.common.exception.TaskExecuteExceptionDecorator.LOGGER
+//import org.slf4j.Logger
+//import org.slf4j.LoggerFactory
+//import java.io.FileNotFoundException
+//import java.io.IOException
+//
+///**
+// * 错误处理
+// */
+//object TaskExecuteExceptionDecorator {
+//
+// val LOGGER: Logger = LoggerFactory.getLogger(TaskExecuteExceptionDecorator::class.java)
+//
+// private val defaultExceptionBase = DefaultExceptionBase()
+//
+// private val factory = mutableMapOf(
+// IllegalStateException::class to IllegalStateExceptionD(),
+// InvalidFormatException::class to InvalidFormatExceptionD(),
+// FileNotFoundException::class to FileNotFoundExceptionD(),
+// RemoteServiceException::class to RemoteServiceExceptionD(),
+// MismatchedInputException::class to MismatchedInputExceptionD(),
+// IOException::class to IOExceptionD(),
+// FileSystemException::class to FileSystemExceptionD()
+// )
+//
+// @Suppress("UNCHECKED_CAST")
+// fun decorate(throwable: Throwable): TaskExecuteException {
+// var exception = throwable
+// return (factory[exception::class] as ExceptionDecorator? ?: exception.cause?.let { cause ->
+// (factory[cause::class] as ExceptionDecorator?)?.let {
+// exception = cause
+// it
+// }
+// } ?: defaultExceptionBase).decorate(exception)
+// }
+//}
+//
+//class DefaultExceptionBase : ExceptionDecorator {
+// override fun decorate(exception: Throwable): TaskExecuteException {
+// return when {
+// exception is TaskExecuteException -> exception
+// // TEE只有一层,所以不遍历cause,防止InputMismatchException 无限循环。
+// exception.cause is TaskExecuteException -> exception.cause as TaskExecuteException
+// else -> {
+// LOGGER.warn("[Worker Error]: ", exception)
+// val defaultMessage = StringBuilder("Unknown system error has occurred with StackTrace:\n")
+// defaultMessage.append(exception.toString())
+// exception.stackTrace.forEach {
+// with(it) {
+// defaultMessage.append(
+// "\n at $className.$methodName($fileName:$lineNumber)"
+// )
+// }
+// }
+// TaskExecuteException(
+// errorMsg = exception.message ?: defaultMessage.toString(),
+// errorType = ErrorType.SYSTEM,
+// errorCode = ErrorCode.SYSTEM_WORKER_LOADING_ERROR,
+// cause = exception
+// )
+// }
+// }
+// }
+//}
+//
+//interface ExceptionDecorator {
+// fun decorate(exception: T): TaskExecuteException
+//}
+//
+//class IllegalStateExceptionD : ExceptionDecorator {
+// override fun decorate(exception: IllegalStateException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "Machine process error: ${exception.message}",
+// errorType = ErrorType.USER,
+// errorCode = ErrorCode.THIRD_PARTY_BUILD_ENV_ERROR,
+// cause = exception
+// )
+// }
+//}
+//
+//class FileNotFoundExceptionD : ExceptionDecorator {
+// override fun decorate(exception: FileNotFoundException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "Machine file not found error: ${exception.message}",
+// errorType = ErrorType.USER,
+// errorCode = ErrorCode.USER_RESOURCE_NOT_FOUND,
+// cause = exception
+// )
+// }
+//}
+//
+//class RemoteServiceExceptionD : ExceptionDecorator {
+//
+// override fun decorate(exception: RemoteServiceException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "THIRD PARTY response error: ${exception.message}",
+// errorType = ErrorType.THIRD_PARTY,
+// errorCode = ErrorCode.THIRD_PARTY_INTERFACE_ERROR,
+// cause = exception
+// )
+// }
+//}
+//
+//class MismatchedInputExceptionD : ExceptionDecorator {
+// override fun decorate(exception: MismatchedInputException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "Plugin data is illegal: ${exception.message}",
+// errorType = ErrorType.PLUGIN,
+// errorCode = ErrorCode.USER_TASK_OPERATE_FAIL,
+// cause = exception
+// )
+// }
+//}
+//
+//class InvalidFormatExceptionD : ExceptionDecorator {
+// override fun decorate(exception: InvalidFormatException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "Plugin data is illegal: ${exception.message}",
+// errorType = ErrorType.PLUGIN,
+// errorCode = ErrorCode.USER_TASK_OPERATE_FAIL,
+// cause = exception
+// )
+// }
+//}
+//
+//class IOExceptionD : ExceptionDecorator {
+// override fun decorate(exception: IOException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "IO Exception: ${exception.message}",
+// errorType = ErrorType.USER,
+// errorCode = ErrorCode.USER_RESOURCE_NOT_FOUND,
+// cause = exception
+// )
+// }
+//}
+//
+//class FileSystemExceptionD : ExceptionDecorator {
+// override fun decorate(exception: FileSystemException): TaskExecuteException {
+// return TaskExecuteException(
+// errorMsg = "FileSystem Exception: ${exception.message}",
+// errorType = ErrorType.USER,
+// errorCode = ErrorCode.USER_RESOURCE_NOT_FOUND,
+// cause = exception
+// )
+// }
+//}
diff --git a/modules/ci-worker/src/main/resources/logback.xml b/modules/ci-worker/src/main/resources/logback.xml
new file mode 100644
index 0000000..3a4b747
--- /dev/null
+++ b/modules/ci-worker/src/main/resources/logback.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+ logback
+
+
+
+ ${LOG_PATH:-.}/logs/${AGENT_LOG_PREFIX:-agent}.log
+
+ ${LOG_PATH:-.}/logs/${AGENT_LOG_PREFIX:-agent}-%d{yyyy-MM-dd}.%i.log
+ 100MB
+ 14
+ 10GB
+
+
+ ${pattern}
+ UTF-8
+
+
+
+
+
+ ${LOG_PATH:-.}/logs/runtime.log
+
+ ${LOG_PATH:-.}/logs/runtime-%d{yyyy-MM-dd}.%i.log
+ 100MB
+ 30
+ 10GB
+
+
+ ${pattern}
+ UTF-8
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/module-system-biz/src/main/java/cd/casic/module/system/controller/admin/auth/http-client.env.json b/modules/module-system-biz/src/main/java/cd/casic/module/system/controller/admin/auth/http-client.env.json
new file mode 100644
index 0000000..f24fcb5
--- /dev/null
+++ b/modules/module-system-biz/src/main/java/cd/casic/module/system/controller/admin/auth/http-client.env.json
@@ -0,0 +1,6 @@
+{
+ "dev": {
+ "baseUrl": "127.0.0.1:48080",
+ "adminTenentId": "1"
+ }
+}
\ No newline at end of file