You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2017/10/11 07:50:56 UTC

[trafficserver] 23/25: Merge branch 'master' into quic-latest

This is an automated email from the ASF dual-hosted git repository.

maskit pushed a commit to branch quic-05
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 6d401d7246d3e47785a1f88ed92af3308c74dd25
Author: Leif Hedstrom <zw...@apache.org>
AuthorDate: Thu Oct 5 11:41:40 2017 -0700

    Merge branch 'master' into quic-latest
    
    * master:
      Change the include from .cc to .h, as Odin intended
      Fix mem leak related to do_os_response() function
      Runroot for traffic_layout
      Fixed typo in cachekey plugin documentation
    
    (cherry picked from commit f322f09d56ff4c9e956807f7a5754fe2274ad6be)
---
 cmd/traffic_cop/traffic_cop.cc                    |   2 +-
 cmd/traffic_crashlog/traffic_crashlog.cc          |   2 +-
 cmd/traffic_ctl/traffic_ctl.cc                    |   2 +-
 cmd/traffic_layout/Makefile.am                    |   6 +-
 cmd/traffic_layout/engine.cc                      | 288 ++++++++++++++++++++++
 cmd/traffic_layout/engine.h                       |  58 +++++
 cmd/traffic_layout/file_system.cc                 | 186 ++++++++++++++
 cmd/traffic_layout/file_system.h                  |  50 ++++
 cmd/traffic_layout/traffic_layout.cc              |  88 ++++++-
 cmd/traffic_manager/traffic_manager.cc            |   2 +-
 doc/admin-guide/plugins/cachekey.en.rst           |   2 +-
 doc/appendices/command-line/traffic_layout.en.rst |  73 ++++++
 lib/ts/Makefile.am                                |   2 +
 lib/ts/runroot.cc                                 |  10 +-
 lib/ts/runroot.h                                  |  35 +++
 mgmt/utils/MgmtSocket.cc                          |   2 +-
 plugins/experimental/ts_lua/ts_lua.c              |   2 +
 proxy/Main.cc                                     |   2 +-
 proxy/http2/Makefile.am                           |   2 +-
 proxy/logcat.cc                                   |   2 +-
 proxy/logstats.cc                                 |   2 +-
 tests/gold_tests/basic/runroot-layout.test.py     |  69 ++++++
 22 files changed, 868 insertions(+), 19 deletions(-)

diff --git a/cmd/traffic_cop/traffic_cop.cc b/cmd/traffic_cop/traffic_cop.cc
index 56737e0..7fcb211 100644
--- a/cmd/traffic_cop/traffic_cop.cc
+++ b/cmd/traffic_cop/traffic_cop.cc
@@ -35,7 +35,7 @@
 #include "RecordsConfig.h"
 #include "ts/ink_cap.h"
 #include "Cop.h"
-#include "ts/runroot.cc"
+#include "ts/runroot.h"
 
 #include <string>
 #include <map>
diff --git a/cmd/traffic_crashlog/traffic_crashlog.cc b/cmd/traffic_crashlog/traffic_crashlog.cc
index c64aded..cca4113 100644
--- a/cmd/traffic_crashlog/traffic_crashlog.cc
+++ b/cmd/traffic_crashlog/traffic_crashlog.cc
@@ -30,7 +30,7 @@
 #include "I_RecProcess.h"
 #include "RecordsConfig.h"
 #include "ts/BaseLogFile.h"
-#include "ts/runroot.cc"
+#include "ts/runroot.h"
 
 static int syslog_mode    = false;
 static int debug_mode     = false;
diff --git a/cmd/traffic_ctl/traffic_ctl.cc b/cmd/traffic_ctl/traffic_ctl.cc
index f09f3b2..32f59d9 100644
--- a/cmd/traffic_ctl/traffic_ctl.cc
+++ b/cmd/traffic_ctl/traffic_ctl.cc
@@ -26,7 +26,7 @@
 #include "ts/I_Layout.h"
 #include "I_RecProcess.h"
 #include "RecordsConfig.h"
-#include "ts/runroot.cc"
+#include "ts/runroot.h"
 
 AppVersionInfo CtrlVersionInfo;
 
diff --git a/cmd/traffic_layout/Makefile.am b/cmd/traffic_layout/Makefile.am
index eb20a0c..4bb3f2a 100644
--- a/cmd/traffic_layout/Makefile.am
+++ b/cmd/traffic_layout/Makefile.am
@@ -28,7 +28,11 @@ AM_LDFLAGS += \
   @OPENSSL_LDFLAGS@
 
 traffic_layout_SOURCES = \
-  traffic_layout.cc
+  traffic_layout.cc \
+  file_system.cc \
+  file_system.h \
+  engine.cc \
+  engine.h
 
 traffic_layout_LDADD = \
   $(top_builddir)/lib/records/librecords_p.a \
diff --git a/cmd/traffic_layout/engine.cc b/cmd/traffic_layout/engine.cc
new file mode 100644
index 0000000..8cb2a32
--- /dev/null
+++ b/cmd/traffic_layout/engine.cc
@@ -0,0 +1,288 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  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.
+*/
+
+// for engine of traffic runroot
+// function introduction in engine.h
+
+#include "ts/runroot.h"
+#include "ts/I_Layout.h"
+#include "ts/ink_error.h"
+#include "ts/ink_args.h"
+#include "ts/I_Version.h"
+#include "ts/ink_file.h"
+
+#include "engine.h"
+#include "file_system.h"
+
+#include <fstream>
+#include <iostream>
+
+// check if user want to force create the ts_runroot
+// return true if user replies Y
+static bool
+check_force()
+{
+  // check for Y/N 3 times
+  for (int i = 0; i < 3; i++) {
+    std::cout << "Are you sure to overwrite and force creating runroot? (irreversible) Y/N: ";
+    std::string input;
+    std::cin >> input;
+    if (input == "Y" || input == "y")
+      return true;
+    if (input == "N" || input == "n")
+      return false;
+  }
+  ink_error("Invalid input Y/N");
+  exit(70);
+}
+
+// check if we can create the runroot using path
+// return true if the path is good to use
+static bool
+check_run_path(const std::string &arg, const int forceflag)
+{
+  if (arg.empty() || arg[0] == '-')
+    return false;
+  if (arg[0] != '-' && arg[0] != '/')
+    ink_fatal("Please provide absolute path");
+
+  std::string path = arg;
+  // check force create
+  if (forceflag == 1) {
+    if (!check_force()) {
+      ink_notice("Force create failed");
+      exit(0);
+    }
+    ink_notice("Forcing creating runroot ...");
+    if (!remove_directory(path)) {
+      ink_warning("Failed removing(overwriting) existing directory - %s", strerror(errno));
+    }
+  }
+  // if directory already exist
+  if (exists(path) && is_directory(path)) {
+    return true;
+  } else {
+    // try to create & remove
+    if (!create_directory(path)) {
+      return false;
+    }
+    remove_directory(path);
+    return true;
+  }
+}
+
+// return true if the path is good to delete
+static bool
+check_delete_path(const std::string &arg)
+{
+  if (arg.empty() || arg[0] == '-')
+    return false;
+  if (arg[0] != '-' && arg[0] != '/')
+    ink_fatal("Please provide absolute path");
+
+  std::ifstream check_file(arg);
+  if (check_file) {
+    return true;
+  }
+  return false;
+}
+
+// the help message for traffic_runroot
+static void
+help_message(const int versionflag, const int runflag, const int cleanflag, const int forceflag)
+{
+  std::cout << "if no path provided, please set Environment variable $TS_RUNROOT" << std::endl;
+  std::cout << "traffic_runroot usage: traffic_runroot [switch] [<path>]" << std::endl;
+  std::cout << "                       traffic_runroot -f [switch] [<path>]\n" << std::endl;
+  std::cout << "==option=====switch=====description=====================================" << std::endl;
+  std::cout << "Run:      --init(-i)     (Initialize the ts_runroot sandbox)" << std::endl;
+  std::cout << "Remove:   --remove(-r)   (remove the ts_runroot sandbox)\n" << std::endl;
+  std::cout << "==flag=======key=========description======================================" << std::endl;
+  std::cout << "Force:    --force   (force to create ts_runroot, only works with init)\n" << std::endl;
+  std::cout << "Program information: traffic_runroot [switch]" << std::endl;
+
+  if (runflag)
+    std::cout << "\ninit example: traffic_runroot init /path/to/sandbox" << std::endl;
+  if (cleanflag)
+    std::cout << "\nremove example: traffic_runroot rm /path/to/sandbox" << std::endl;
+  if (forceflag)
+    std::cout << "\nforce example: traffic_runroot --force init /path/to/sandbox" << std::endl;
+}
+
+// the parsing function for traffic runroot program
+// set the flag & path appropriately
+void
+RunrootEngine::runroot_parse()
+{
+  int i = 0;
+  while (i < _argc) {
+    std::string argument = _argv[i];
+    // set help, verion, force flag
+    if (argument == "-h" || argument == "--help") {
+      help_flag = 1;
+    }
+    if (argument == "-V" || argument == "--version") {
+      version_flag = 1;
+    }
+    if (argument == "-f" || argument == "--force") {
+      force_flag = 1;
+    }
+    // set init flag & sandbox path
+    if (argument == "--init" || argument == "-i") {
+      run_flag = 1;
+      if (i == _argc - 1)
+        break;
+      if (!check_run_path(_argv[i + 1], force_flag)) {
+        ++i;
+        continue;
+      }
+      run_path = _argv[i + 1];
+      ++i;
+    }
+    // set remove flag & sandbox path
+    if (argument == "--remove" || argument == "-r") {
+      clean_flag = 1;
+      if (i == _argc - 1)
+        break;
+      if (!check_delete_path(_argv[i + 1])) {
+        ++i;
+        continue;
+      }
+      clean_path = _argv[i + 1];
+      ++i;
+    }
+    ++i;
+  }
+  // check output help or not
+  if (help_flag == 1) {
+    help_message(version_flag, run_flag, clean_flag, force_flag);
+    exit(0);
+  }
+  if (version_flag == 1) {
+    // get version info
+    AppVersionInfo appVersionInfo;
+    appVersionInfo.setup(PACKAGE_NAME, "traffic_runroot", PACKAGE_VERSION, __DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, "");
+    ink_fputln(stdout, appVersionInfo.FullVersionInfoStr);
+    exit(0);
+  }
+  if (run_flag == 1 && clean_flag == 1) {
+    ink_fatal("Cannot run and clean in the same time");
+  }
+  if (force_flag == 1 && run_flag == 0) {
+    ink_fatal("Nothing to force");
+  }
+}
+
+// for cleanning the parent of bin / cwd
+// return the path if we can clean the bin / cwd
+const static std::string
+clean_parent(const std::string &bin_path)
+{
+  char cwd[MAX_CWD_LEN];
+  getcwd(cwd, sizeof(cwd));
+  std::string RealBinPath = realpath(bin_path.c_str(), nullptr); // bin path
+
+  std::vector<std::string> TwoPath = {RealBinPath, cwd};
+  for (auto it : TwoPath) {
+    std::string path = check_parent_path(it);
+    if (path.size() != 0) {
+      return path;
+    }
+  }
+  return "";
+}
+
+// the function for removing the runroot
+bool
+RunrootEngine::clean_runroot()
+{
+  if (clean_flag == 1) {
+    std::string clean_root;
+    if (!clean_path.empty()) {
+      clean_root = clean_path;
+    } else {
+      // no clean path provided get the environment
+      if (getenv("TS_RUNROOT") != nullptr) {
+        clean_root = getenv("TS_RUNROOT");
+      } else {
+        // no path & environment, get parents of bin/cwd
+        clean_root = clean_parent(_argv[0]);
+        if (clean_root.empty())
+          ink_fatal("Nothing to clean");
+      }
+    }
+    append_slash(clean_root);
+
+    // if we can find the yaml, then clean it
+    std::ifstream check_file(clean_root + "runroot_path.yaml");
+    if (check_file.good()) {
+      if (!remove_directory(clean_root)) {
+        ink_fatal("Error cleaning directory - %s", strerror(errno));
+      }
+    } else {
+      ink_fatal("invalid path to clean (no yaml file found)");
+    }
+    return true;
+  }
+
+  // no clean
+  return false;
+}
+
+// copy the stuff from original_root to ts_runroot
+// fill in the global map for yaml file emitting later
+void
+RunrootEngine::copy_runroot(const std::string &original_root, const std::string &ts_runroot)
+{
+  // map the original build time directory
+  std::unordered_map<std::string, std::string> original_map;
+
+  original_map["exec_prefix"]   = TS_BUILD_EXEC_PREFIX;
+  original_map["bindir"]        = TS_BUILD_BINDIR;
+  original_map["sbindir"]       = TS_BUILD_SBINDIR;
+  original_map["sysconfdir"]    = TS_BUILD_SYSCONFDIR;
+  original_map["datadir"]       = TS_BUILD_DATADIR;
+  original_map["includedir"]    = TS_BUILD_INCLUDEDIR;
+  original_map["libdir"]        = TS_BUILD_LIBDIR;
+  original_map["libexecdir"]    = TS_BUILD_LIBEXECDIR;
+  original_map["localstatedir"] = TS_BUILD_LOCALSTATEDIR;
+  original_map["runtimedir"]    = TS_BUILD_RUNTIMEDIR;
+  original_map["logdir"]        = TS_BUILD_LOGDIR;
+  original_map["mandir"]        = TS_BUILD_MANDIR;
+  original_map["infodir"]       = TS_BUILD_INFODIR;
+  original_map["cachedir"]      = TS_BUILD_CACHEDIR;
+
+  // copy each directory to the runroot path
+  // symlink the executables
+  // set up path_map for yaml to emit key-value pairs
+  ink_notice("Copying from the original root...");
+  for (auto it : original_map) {
+    std::string old_path = Layout::relative_to(original_root, it.second);
+    std::string new_path = ts_runroot + it.second;
+    if (!copy_directory(old_path, new_path)) {
+      ink_warning("Copy failed for %s - %s", it.first.c_str(), strerror(errno));
+    }
+    path_map[it.first] = ts_runroot + it.second;
+  }
+  path_map["prefix"] = ts_runroot;
+}
diff --git a/cmd/traffic_layout/engine.h b/cmd/traffic_layout/engine.h
new file mode 100644
index 0000000..c68ef51
--- /dev/null
+++ b/cmd/traffic_layout/engine.h
@@ -0,0 +1,58 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  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.
+*/
+
+#pragma once
+
+#include <vector>
+#include <string>
+#include <unordered_map>
+
+// structure for informaiton of the runroot passing around
+struct RunrootEngine {
+  // the parsing function for traffic runroot program
+  void runroot_parse();
+
+  // the function for removing the runroot
+  // return true upon success, false upon failure
+  bool clean_runroot();
+
+  // copy the stuff from original_root to ts_runroot
+  // fill in the global map for yaml file emitting later
+  void copy_runroot(const std::string &original_root, const std::string &ts_runroot);
+
+  // the pass in arguments
+  int _argc;
+  std::vector<std::string> _argv;
+  // the flag for command line parsing
+  int help_flag    = 0;
+  int version_flag = 0;
+  int run_flag     = 0;
+  int clean_flag   = 0;
+  int force_flag   = 0;
+  // the path for create & remove
+  std::string run_path;
+  std::string clean_path;
+
+  // map for yaml file emit
+  std::unordered_map<std::string, std::string> path_map;
+};
diff --git a/cmd/traffic_layout/file_system.cc b/cmd/traffic_layout/file_system.cc
new file mode 100644
index 0000000..8730f93
--- /dev/null
+++ b/cmd/traffic_layout/file_system.cc
@@ -0,0 +1,186 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  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.
+*/
+
+// funciton for file system management
+// including: make directory (with parents), copy directory (recursively), remove directory (recursively)
+
+#include "ts/ink_error.h"
+
+#include "file_system.h"
+
+#include <iostream>
+#include <fstream>
+#include <ftw.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ts/I_Layout.h>
+
+// global variables for copy function
+static std::string dst_root;
+static std::string src_root;
+
+void
+append_slash(std::string &path)
+{
+  if (path.back() != '/')
+    path.append("/");
+}
+
+void
+remove_slash(std::string &path)
+{
+  if (path.back() == '/')
+    path.pop_back();
+}
+
+bool
+exists(std::string const &dir)
+{
+  struct stat buffer;
+  int result = stat(dir.c_str(), &buffer);
+  return (!result) ? true : false;
+}
+
+bool
+is_directory(std::string const &directory)
+{
+  struct stat buffer;
+  int result = stat(directory.c_str(), &buffer);
+  return (!result && (S_IFDIR & buffer.st_mode)) ? true : false;
+}
+
+bool
+create_directory(const std::string &dir)
+{
+  std::string s = dir;
+  append_slash(s);
+
+  if (exists(dir) && is_directory(dir)) {
+    return true;
+  }
+
+  int ret = 0, pos = 0, pos1 = 0;
+  if ((s[0] == '.') || (s[0] == '/')) {
+    pos1 = s.find("/") + 1;
+  }
+  pos = s.find("/", pos1);
+
+  ret  = mkdir(s.substr(0, pos).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+  pos1 = pos + 1;
+  // create directory one layer by one layer
+  while (1) {
+    pos = s.find("/", pos1);
+    if ((size_t)pos == s.npos)
+      break;
+    ret  = mkdir(s.substr(0, pos).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+    pos1 = pos + 1;
+  }
+  if (ret)
+    return false;
+  else
+    return true;
+}
+
+static int
+remove_function(const char *path, const struct stat *s, int flag, struct FTW *f)
+{
+  int (*rm_func)(const char *);
+
+  switch (flag) {
+  default:
+    rm_func = unlink;
+    break;
+  case FTW_DP:
+    rm_func = rmdir;
+  }
+  if (rm_func(path) == -1) {
+    ink_notice("Failed removing directory: %s\n", strerror(errno));
+    return -1;
+  }
+  return 0;
+}
+
+// remove directory recursively using nftw to iterate
+bool
+remove_directory(const std::string &dir)
+{
+  std::string path = dir;
+  remove_slash(path);
+  if (nftw(path.c_str(), remove_function, OPEN_MAX_FILE, FTW_DEPTH))
+    return false;
+  else
+    return true;
+}
+
+static int
+copy_function(const char *src_path, const struct stat *sb, int flag)
+{
+  // src path no slash
+  std::string full_src_path = src_path;
+  if (full_src_path == src_root) {
+    if (!create_directory(dst_root))
+      ink_fatal("create directory failed during copy");
+    return 0;
+  }
+  std::string src_back = full_src_path.substr(src_root.size() + 1);
+  std::string dst_path = dst_root + src_back;
+
+  switch (flag) {
+  case FTW_D:
+    // create directory for FTW_D type
+    if (!create_directory(dst_path))
+      ink_fatal("create directory failed during copy");
+    break;
+  case FTW_F:
+    // for files if bin executable mode, symlink
+    if (sb->st_mode == BIN_MODE) {
+      if (symlink(src_path, dst_path.c_str()) != 0) {
+        if (errno != EEXIST)
+          ink_warning("failed to create symbolic link - %s", strerror(errno));
+      }
+    } else {
+      // for normal other files
+      std::ifstream src(src_path, std::ios::binary);
+      std::ofstream dst(dst_path, std::ios::binary);
+      dst << src.rdbuf();
+      chmod(dst_path.c_str(), sb->st_mode);
+    }
+  }
+  return 0;
+}
+
+// copy directory recursively using ftw to iterate
+bool
+copy_directory(const std::string &src, const std::string &dst)
+{
+  src_root = src;
+  dst_root = dst;
+  remove_slash(src_root);
+  append_slash(dst_root);
+
+  if (ftw(src_root.c_str(), copy_function, OPEN_MAX_FILE))
+    return false;
+  else
+    return true;
+}
diff --git a/cmd/traffic_layout/file_system.h b/cmd/traffic_layout/file_system.h
new file mode 100644
index 0000000..093f60b
--- /dev/null
+++ b/cmd/traffic_layout/file_system.h
@@ -0,0 +1,50 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  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.
+*/
+
+#pragma once
+
+#include <string>
+
+// binary executable mode (for symlink)
+#define BIN_MODE 33261
+
+// some system does not have OPEN_MAX defined
+// size can be changed accordingly
+#define OPEN_MAX_FILE 256
+
+// append slash & remove slash of path for convinient use
+void append_slash(std::string &path);
+
+void remove_slash(std::string &path);
+
+// some checks for directory exist or is it a directory
+bool exists(std::string const &dir);
+
+bool is_directory(std::string const &directory);
+
+// for file system
+bool create_directory(const std::string &dir);
+
+bool remove_directory(const std::string &dir);
+
+bool copy_directory(const std::string &src, const std::string &dst);
diff --git a/cmd/traffic_layout/traffic_layout.cc b/cmd/traffic_layout/traffic_layout.cc
index b680145..36fdf2e 100644
--- a/cmd/traffic_layout/traffic_layout.cc
+++ b/cmd/traffic_layout/traffic_layout.cc
@@ -27,7 +27,12 @@
 #include "ts/I_Layout.h"
 #include "I_RecProcess.h"
 #include "RecordsConfig.h"
-#include "ts/runroot.cc"
+#include "ts/runroot.h"
+#include "engine.h"
+#include "file_system.h"
+
+#include <iostream>
+#include <fstream>
 
 // Command line arguments (parsing)
 struct CommandLineArgs {
@@ -42,6 +47,9 @@ const ArgumentDescription argument_descriptions[] = {
   {"layout", 'l', "Show the layout (this is the default with no options given)", "T", &cl.layout, nullptr, nullptr},
   {"features", 'f', "Show the compiled features", "T", &cl.features, nullptr, nullptr},
   {"json", 'j', "Produce output in JSON format (when supported)", "T", &cl.json, nullptr, nullptr},
+  {"init", 'i', "Initialize the ts_runroot sandbox (details in traffic_layout --init -h)", nullptr, nullptr, nullptr, nullptr},
+  {"remove", 'r', "remove the ts_runroot sandbox (details in traffic_layout --remove -h)", nullptr, nullptr, nullptr, nullptr},
+  {"force", '-', "force flag for init (details in traffic_layout --force -h)", nullptr, nullptr, nullptr, nullptr},
 
   HELP_ARGUMENT_DESCRIPTION(),
   VERSION_ARGUMENT_DESCRIPTION(),
@@ -175,9 +183,85 @@ produce_layout(bool json)
   }
 }
 
+void
+traffic_runroot(int argc, const char **argv)
+{
+  // runroot engine for operations
+  RunrootEngine engine;
+  engine._argc = argc;
+  int i        = 0;
+  while (argv[i]) {
+    engine._argv.push_back(argv[i]);
+    ++i;
+  }
+
+  // parse the command line & put into global variable
+  engine.runroot_parse();
+
+  // check to clean the runroot or not
+  if (engine.clean_runroot())
+    return;
+
+  // start the runroot creating stuff
+  std::string original_root = TS_BUILD_PREFIX;
+  append_slash(original_root);
+
+  // setting up ts_runroot
+  // Use passed in parameter, else use ENV variable
+  std::string ts_runroot;
+  if (!engine.run_path.empty()) {
+    ts_runroot = engine.run_path;
+  } else {
+    if (getenv("TS_RUNROOT") != nullptr) {
+      ts_runroot = getenv("TS_RUNROOT");
+      ink_notice("Using TS_RUNROOT Env variable");
+    } else {
+      ink_fatal("Invalid ts_runroot path\n(please set command line path or Environment variable $TS_RUNROOT)");
+    }
+  }
+
+  // handle the ts_runroot
+  // ts runroot must be an accessible path
+  append_slash(ts_runroot);
+  std::ifstream check_file(ts_runroot + "runroot_path.yaml");
+  if (check_file.good()) {
+    // if the path already ts_runroot, use it
+    ink_notice("Using existing TS_RUNROOT...");
+    ink_notice("Please remove the old TS_RUNROOT if new runroot is needed \n(usage: traffic_runroot rm /path/...)");
+    return;
+  } else if (exists(ts_runroot) && is_directory(ts_runroot)) {
+    ink_fatal("directory already exist");
+  }
+
+  // create new root & copy from original to new runroot. then fill in the map
+  engine.copy_runroot(original_root, ts_runroot);
+
+  // create and emit to yaml file the key value pairs of path
+  std::ofstream yamlfile;
+  std::string yaml_path = ts_runroot + "runroot_path.yaml";
+  yamlfile.open(yaml_path);
+
+  for (auto it : engine.path_map) {
+    // out put key value pairs of path
+    yamlfile << it.first << ": " << it.second << std::endl;
+  }
+  ink_notice("\nTS runroot initialized");
+
+  return;
+}
+
 int
-main(int /* argc ATS_UNUSED */, const char **argv)
+main(int argc, const char **argv)
 {
+  // check for traffic_runroot operations
+  for (int i = 0; i < argc; i++) {
+    if (!strcmp(argv[i], "--init") || !strcmp(argv[i], "--remove") || !strcmp(argv[i], "-i") || !strcmp(argv[i], "-r") ||
+        !strcmp(argv[i], "--force")) {
+      traffic_runroot(argc, argv);
+      exit(0);
+    }
+  }
+  // normal print out layout operation
   AppVersionInfo appVersionInfo;
 
   appVersionInfo.setup(PACKAGE_NAME, "traffic_layout", PACKAGE_VERSION, __DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, "");
diff --git a/cmd/traffic_manager/traffic_manager.cc b/cmd/traffic_manager/traffic_manager.cc
index b5e35fa..4080d37 100644
--- a/cmd/traffic_manager/traffic_manager.cc
+++ b/cmd/traffic_manager/traffic_manager.cc
@@ -27,7 +27,7 @@
 #include "ts/ink_sock.h"
 #include "ts/ink_args.h"
 #include "ts/ink_syslog.h"
-#include "ts/runroot.cc"
+#include "ts/runroot.h"
 
 #include "WebMgmtUtils.h"
 #include "MgmtUtils.h"
diff --git a/doc/admin-guide/plugins/cachekey.en.rst b/doc/admin-guide/plugins/cachekey.en.rst
index 39f7c55..b36e6ee 100644
--- a/doc/admin-guide/plugins/cachekey.en.rst
+++ b/doc/admin-guide/plugins/cachekey.en.rst
@@ -167,7 +167,7 @@ All parameters are optional, and if not used, their default values are as mentio
 
 Cache key elements separator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-* ``--separator=<string>`` - the cache key is constructed by extracting elements from HTTP URI and headers or by using the UA classifiers and they are appended during the key construction and separated by ``/`` (by default). This options allows to override the dafault separator to any string (including an empty string)
+* ``--separator=<string>`` - the cache key is constructed by extracting elements from HTTP URI and headers or by using the UA classifiers and they are appended during the key construction and separated by ``/`` (by default). This options allows to override the default separator to any string (including an empty string).
 
 
 Detailed examples and troubleshooting
diff --git a/doc/appendices/command-line/traffic_layout.en.rst b/doc/appendices/command-line/traffic_layout.en.rst
new file mode 100644
index 0000000..bd790f1
--- /dev/null
+++ b/doc/appendices/command-line/traffic_layout.en.rst
@@ -0,0 +1,73 @@
+.. 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.
+
+.. include:: ../../common.defs
+
+.. _traffic_cop:
+
+traffic_layout
+*****************
+
+Description
+=============
+Document for the special functionality of ``runroot`` inside ``traffic_layout`` program
+This feature is for the setup of traffic server runroot.
+It will create a runtime sandbox for any program of traffic server to run under.
+
+1. Use program traffic_layout to create sandbox.
+2. Run any program use the sandbox with ``--run-root=/path`` or ``--run-root``
+
+How it works:
+--------------
+
+1. Create a sandbox directory for programs to run under
+2. Copy and symlink build time directories and files to sandbox, allowing users to modify freely.
+3. Emit a yaml file that defines layout structure for other programs to use.
+
+Options:
+=============
+1. Initialize the runroot: ::
+
+    traffic_layout --init /path/to/sandbox/
+
+ If no path is found, it will find the ENV variable $TS_RUNROOT
+
+2. Remove the runroot: ::
+
+    traffic_layout --remove /path/to/sandbox/
+
+ Remove the sandbox we created(check yaml file).
+ If no path provided, it will find the ENV variable $TS_RUNROOT.
+ If $TS_RUNROOT not found, it will find bin executing path & current working directory.
+
+3. Force flag for creating: ::
+
+    traffic_runroot --force --init /path/to/sandbox
+
+ Force create sandbox and overwrite existing directory 
+
+Usage for other programs:
+==============================================
+Use pass in path or use Environment variable $TS_RUNROOT.
+If both not found, program will try to find bin path & current woring directory. ::
+
+    trafficserver --run-root=/path/to/runroot
+    trafficserver --run-root
+
+Notes
+==========
+Path to sandbox must be an absolute path.
diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am
index efd87d5..5880f5c 100644
--- a/lib/ts/Makefile.am
+++ b/lib/ts/Makefile.am
@@ -178,6 +178,8 @@ libtsutil_la_SOURCES = \
   Regression.cc \
   Regression.h \
   Result.h \
+  runroot.cc \
+  runroot.h \
   signals.cc \
   signals.h \
   SimpleTokenizer.h \
diff --git a/lib/ts/runroot.cc b/lib/ts/runroot.cc
index ef49ce0..4586f79 100644
--- a/lib/ts/runroot.cc
+++ b/lib/ts/runroot.cc
@@ -38,19 +38,17 @@ datadir, libexecdir, libdir, runtimedir, infodir, cachedir.
 */
 
 #include "ts/ink_error.h"
+#include "runroot.h"
 
 #include <vector>
-#include <string>
 #include <fstream>
 #include <set>
 #include <unistd.h>
 
-#define MAX_CWD_LEN 1024
-
 // the function for the checking of the yaml file in parent path
 // if found return the parent path containing the yaml file
-static std::string
-check_parent_path(const std::string &path, bool json = false)
+std::string
+check_parent_path(const std::string &path, bool json)
 {
   std::string whole_path = path;
   if (whole_path.back() == '/')
@@ -81,7 +79,7 @@ is_directory(const char *directory)
 
 // handler for ts runroot
 void
-runroot_handler(const char **argv, bool json = false)
+runroot_handler(const char **argv, bool json)
 {
   std::string command = {};
   std::string arg     = {};
diff --git a/lib/ts/runroot.h b/lib/ts/runroot.h
new file mode 100644
index 0000000..ee0118b
--- /dev/null
+++ b/lib/ts/runroot.h
@@ -0,0 +1,35 @@
+/** @file
+
+  A brief file prefix
+
+  @section license License
+
+  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.
+*/
+
+// runroot handler for TS_RUNROOT
+// detailed information in runroot.cc
+
+#pragma once
+
+#include <string>
+
+#define MAX_CWD_LEN 1024
+
+std::string check_parent_path(const std::string &path, bool json = false);
+
+void runroot_handler(const char **argv, bool json = false);
diff --git a/mgmt/utils/MgmtSocket.cc b/mgmt/utils/MgmtSocket.cc
index 9c372a8..bbb0c69 100644
--- a/mgmt/utils/MgmtSocket.cc
+++ b/mgmt/utils/MgmtSocket.cc
@@ -23,7 +23,7 @@
 
 #include "ts/ink_platform.h"
 #include "ts/ink_assert.h"
-#include <ts/ink_cap.cc>
+#include "ts/ink_cap.h"
 #include "MgmtSocket.h"
 
 #if HAVE_UCRED_H
diff --git a/plugins/experimental/ts_lua/ts_lua.c b/plugins/experimental/ts_lua/ts_lua.c
index 59cfb9e..554a327 100644
--- a/plugins/experimental/ts_lua/ts_lua.c
+++ b/plugins/experimental/ts_lua/ts_lua.c
@@ -194,6 +194,8 @@ ts_lua_remap_plugin_init(void *ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
 
   lua_getglobal(L, (remap ? TS_LUA_FUNCTION_REMAP : TS_LUA_FUNCTION_OS_RESPONSE));
   if (lua_type(L, -1) != LUA_TFUNCTION) {
+    lua_pop(L, 1);
+    ts_lua_destroy_http_ctx(http_ctx);
     TSMutexUnlock(main_ctx->mutexp);
     return TSREMAP_NO_REMAP;
   }
diff --git a/proxy/Main.cc b/proxy/Main.cc
index 12f83df..32a8dd3 100644
--- a/proxy/Main.cc
+++ b/proxy/Main.cc
@@ -37,7 +37,7 @@
 #include "ts/ink_stack_trace.h"
 #include "ts/ink_syslog.h"
 #include "ts/hugepages.h"
-#include "ts/runroot.cc"
+#include "ts/runroot.h"
 
 #include "api/ts/ts.h" // This is sadly needed because of us using TSThreadInit() for some reason.
 
diff --git a/proxy/http2/Makefile.am b/proxy/http2/Makefile.am
index 3124e46..848b71c 100644
--- a/proxy/http2/Makefile.am
+++ b/proxy/http2/Makefile.am
@@ -89,7 +89,7 @@ test_HPACK_LDADD = \
   $(top_builddir)/mgmt/libmgmt_p.la \
   $(top_builddir)/proxy/shared/libUglyLogStubs.a \
   @LIBTCL@ \
-  @HWLOC_LIBS@ @LIBCAP@
+  @HWLOC_LIBS@
 
 test_HPACK_SOURCES = \
   test_HPACK.cc \
diff --git a/proxy/logcat.cc b/proxy/logcat.cc
index 98f8c82..58144ca 100644
--- a/proxy/logcat.cc
+++ b/proxy/logcat.cc
@@ -24,7 +24,7 @@
 #include "ts/ink_platform.h"
 #include "ts/ink_args.h"
 #include "ts/I_Layout.h"
-#include "ts/runroot.cc"
+#include "ts/runroot.h"
 
 #define PROGRAM_NAME "traffic_logcat"
 #define MAX_LOGBUFFER_SIZE 65536
diff --git a/proxy/logstats.cc b/proxy/logstats.cc
index 8007a42..6ab7e93 100644
--- a/proxy/logstats.cc
+++ b/proxy/logstats.cc
@@ -29,7 +29,7 @@
 #include "ts/HashFNV.h"
 #include "ts/ink_args.h"
 #include "ts/MatcherUtils.h"
-#include "ts/runroot.cc"
+#include "ts/runroot.h"
 
 // Includes and namespaces etc.
 #include "LogStandalone.cc"
diff --git a/tests/gold_tests/basic/runroot-layout.test.py b/tests/gold_tests/basic/runroot-layout.test.py
new file mode 100644
index 0000000..b1846c9
--- /dev/null
+++ b/tests/gold_tests/basic/runroot-layout.test.py
@@ -0,0 +1,69 @@
+'''
+'''
+#  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.
+
+import os
+import sys
+import time
+
+Test.Summary = '''
+Test that use for runroot from traffic_layout is all functional.
+'''
+Test.ContinueOnFail = True
+
+p = Test.MakeATSProcess("ts")
+path = os.path.join(p.Env['TS_ROOT'], "runroot")
+
+# normal init from pass in path
+tr = Test.AddTestRun("Test traffic_layout init")
+tr.Processes.Default.Command = "$ATS_BIN/traffic_layout --init " + path
+tr.Processes.Default.ReturnCode = 0
+d = tr.Disk.Directory(path)
+d.Exists = True
+f = tr.Disk.File(os.path.join(path, "runroot_path.yaml"))
+f.Exists = True
+
+# remove from pass in path
+tr = Test.AddTestRun("Test traffoc_layout remove")
+tr.Processes.Default.Command = "$ATS_BIN/traffic_layout --remove " + path
+tr.Processes.Default.ReturnCode = 0
+d = tr.Disk.Directory(path)
+d.Exists = False
+f = tr.Disk.File(os.path.join(path, "runroot_path.yaml"))
+f.Exists = False
+
+path += '/'
+
+#use env variable to init
+tr = Test.AddTestRun("Test traffic_layout ENV init")
+tr.Processes.Default.Env["TS_RUNROOT"] = path
+tr.Processes.Default.Command = "$ATS_BIN/traffic_layout --init"
+tr.Processes.Default.ReturnCode = 0
+d = tr.Disk.Directory(path)
+d.Exists = True
+f = tr.Disk.File(os.path.join(path, "runroot_path.yaml"))
+f.Exists = True
+
+#use env variable to remove
+tr = Test.AddTestRun("Test traffic_layout ENV remove")
+tr.Processes.Default.Env["TS_RUNROOT"] = path
+tr.Processes.Default.Command = "$ATS_BIN/traffic_layout --remove"
+tr.Processes.Default.ReturnCode = 0
+d = tr.Disk.Directory(path)
+d.Exists = False
+f = tr.Disk.File(os.path.join(path, "runroot_path.yaml"))
+f.Exists = False
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>.