Apache Mesos
switchboard.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __MESOS_CONTAINERIZER_IO_SWITCHBOARD_HPP__
18 #define __MESOS_CONTAINERIZER_IO_SWITCHBOARD_HPP__
19 
20 #include <string>
21 
22 #include <process/future.hpp>
23 #include <process/http.hpp>
24 #include <process/owned.hpp>
25 #include <process/socket.hpp>
26 
27 #include <stout/try.hpp>
28 
31 
32 #include "slave/flags.hpp"
33 
35 
36 namespace mesos {
37 namespace internal {
38 namespace slave {
39 
40 // The `IOSwitchboard` is a component in the agent whose job it is to
41 // instantiate an `IOSwitchboardServer` that can be used to feed the
42 // stdin to a container from an external source, as well as redirect
43 // the stdin/stdout of a container to multiple targets.
44 //
45 // The primary motivation of this component is to enable support in
46 // mesos similar to `docker attach` and `docker exec` whereby an
47 // external client can attach to the stdin/stdout/stderr of a running
48 // container as well as launch arbitrary subcommands inside a
49 // container and attach to its stdin/stdout/stderr.
50 //
51 // The I/O switchboard is integrated with `MesosContainerizer` through
52 // the `Isolator` interface.
54 {
55 public:
57  const Flags& flags,
58  bool local);
59 
60  ~IOSwitchboard() override;
61 
62  bool supportsNesting() override;
63  bool supportsStandalone() override;
64 
66  const std::vector<mesos::slave::ContainerState>& states,
67  const hashset<ContainerID>& orphans) override;
68 
70  const ContainerID& containerId,
71  const mesos::slave::ContainerConfig& containerConfig) override;
72 
74  const ContainerID& containerId) override;
75 
77  const ContainerID& containerId) override;
78 
79  // Connect to the `IOSwitchboard` associated with `containerId`.
81  const ContainerID& containerId) const;
82 
83  // Transfer ownership of a `ContainerIO` struct for a given
84  // container out of the `IOSwitchboard` and into the caller.
86  const ContainerID& containerID);
87 
88  // Helper function that returns `true` if `IOSwitchboardServer`
89  // needs to be enabled for the given `ContainerConfig`. It must
90  // be enabled for `DEBUG` containers and ones that need `TTYInfo`.
91  static bool requiresServer(
92  const mesos::slave::ContainerConfig& containerConfig);
93 
94 private:
95  struct Info
96  {
97  Info(Option<pid_t> _pid, const process::Future<Option<int>>& _status)
98  : pid(_pid),
99  status(_status) {}
100 
101  Option<pid_t> pid;
104  };
105 
107  const Flags& flags,
108  bool local,
110 
112  const ContainerID& containerId,
113  const mesos::slave::ContainerConfig& containerConfig,
114  const mesos::slave::ContainerIO& loggerIO);
115 
117  const ContainerID& containerId) const;
118 
120  const ContainerID& containerID);
121 
122 #ifndef __WINDOWS__
123  void reaped(
124  const ContainerID& containerId,
125  const process::Future<Option<int>>& future);
126 #endif // __WINDOWS__
127 
128  Flags flags;
129  bool local;
132 
133  // We use a separate hashmap to hold the `ContainerIO` for each
134  // container because we need to maintain this information even in
135  // the case were we only instantiate the logger and never spawn an
136  // `IOSwitchbaordProcess`. Also, the lifetime of the `ContainerIO`
137  // is shorter lived than the `Info` struct, as it should be removed
138  // from this hash as soon as ownership is transferred out of the
139  // `IOSwitchboard` via a call to `extractContainerIO()`.
141 };
142 
143 
144 #ifndef __WINDOWS__
145 // The `IOSwitchboardServer` encapsulates the server side logic for
146 // redirecting the `stdin/stdout/stderr` of a container to/from
147 // multiple sources/targets. It runs an HTTP server over a unix domain
148 // socket in order to process incoming `ATTACH_CONTAINER_INPUT` and
149 // `ATTACH_CONTAINER_OUTPUT` calls and redirect a containers
150 // `stdin/stdout/stderr` through them. In 'local' mode, it is run
151 // inside the agent itself. In 'non-local' mode, it is run as an
152 // external process to survive agent restarts.
153 class IOSwitchboardServerProcess;
154 
155 
157 {
158 public:
159  // The set of flags to pass to the io switchboard server when
160  // launched in an external binary.
161  struct Flags : public virtual flags::FlagsBase
162  {
164  {
165  setUsageMessage(
166  "Usage: " + stringify(NAME) + " [options]\n"
167  "The io switchboard server is designed to feed stdin to a container\n"
168  "from an external source, as well as redirect the stdin/stdout of a\n"
169  "container to multiple targets.\n"
170  "\n"
171  "It runs an HTTP server over a unix domain socket in order to process\n"
172  "incoming `ATTACH_CONTAINER_INPUT` and `ATTACH_CONTAINER_OUTPUT`\n"
173  "calls and redirect a containers `stdin/stdout/stderr` through them.\n"
174  "\n"
175  "The primary motivation of this component is to enable support in\n"
176  "mesos similar to `docker attach` and `docker exec` whereby an\n"
177  "external client can attach to the stdin/stdout/stderr of a running\n"
178  "container as well as launch arbitrary subcommands inside a container\n"
179  "and attach to its stdin/stdout/stderr.\n");
180 
181  add(&Flags::tty,
182  "tty",
183  "If a pseudo terminal has been allocated for the container.",
184  false);
185 
186  add(&Flags::stdin_to_fd,
187  "stdin_to_fd",
188  "The file descriptor where incoming stdin data should be written.");
189 
190  add(&Flags::stdout_from_fd,
191  "stdout_from_fd",
192  "The file descriptor that should be read to consume stdout data.");
193 
194  add(&Flags::stdout_to_fd,
195  "stdout_to_fd",
196  "A file descriptor where data read from\n"
197  "'stdout_from_fd' should be redirected to.");
198 
199  add(&Flags::stderr_from_fd,
200  "stderr_from_fd",
201  "The file descriptor that should be read to consume stderr data.");
202 
203  add(&Flags::stderr_to_fd,
204  "stderr_to_fd",
205  "A file descriptor where data read from\n"
206  "'stderr_from_fd' should be redirected to.");
207 
208  add(&Flags::wait_for_connection,
209  "wait_for_connection",
210  "A boolean indicating whether the server should wait for the\n"
211  "first connection before reading any data from the '*_from_fd's.",
212  false);
213 
214  add(&Flags::socket_path,
215  "socket_address",
216  "The path of the unix domain socket this\n"
217  "io switchboard should attach itself to.");
218 
219  add(&Flags::heartbeat_interval,
220  "heartbeat_interval",
221  "A heartbeat interval (e.g. '5secs', '10mins') for messages to\n"
222  "be sent to any open 'ATTACH_CONTAINER_OUTPUT' connections.");
223  }
224 
225  bool tty;
234  };
235 
236  static const char NAME[];
237 
239  bool tty,
240  int stdinToFd,
241  int stdoutFromFd,
242  int stdoutToFd,
243  int stderrFromFd,
244  int stderrToFd,
245  const std::string& socketPath,
246  bool waitForConnection = false,
247  Option<Duration> heartbeatInterval = None());
248 
250 
251  // Run the io switchboard server.
253 
254  // Forcibly unblock the io switchboard server if it
255  // has been started with `waitForConnection` set to `true`.
257 
258 private:
260  bool tty,
261  int stdinToFd,
262  int stdoutFromFd,
263  int stdoutToFd,
264  int stderrFromFd,
265  int stderrToFd,
267  bool waitForConnection,
268  Option<Duration> heartbeatInterval);
269 
271 };
272 #endif // __WINDOWS__
273 
274 } // namespace slave {
275 } // namespace internal {
276 } // namespace mesos {
277 
278 #endif // __MESOS_CONTAINERIZER_IO_SWITCHBOARD_HPP__
process::Future< Option< mesos::slave::ContainerLaunchInfo > > prepare(const ContainerID &containerId, const mesos::slave::ContainerConfig &containerConfig) override
Definition: check.hpp:33
process::Future< mesos::slave::ContainerLimitation > watch(const ContainerID &containerId) override
bool tty
Definition: switchboard.hpp:225
Definition: switchboard.hpp:156
Option< int > stdout_to_fd
Definition: switchboard.hpp:228
virtual process::Future< ContainerStatus > status(const ContainerID &containerId)
Definition: isolator.hpp:139
const std::string NAME
Definition: logrotate.hpp:38
An abstraction around the IO classes used to redirect stdin/stdout/stderr to/from a container by the ...
Definition: containerizer.hpp:37
Definition: flags.hpp:39
Future< Nothing > add(const T &metric)
Definition: metrics.hpp:95
Option< int > stdin_to_fd
Definition: switchboard.hpp:226
Definition: hashmap.hpp:38
Option< int > stderr_from_fd
Definition: switchboard.hpp:229
process::Future< process::http::Connection > connect(const ContainerID &containerId) const
process::Future< Nothing > recover(const std::vector< mesos::slave::ContainerState > &states, const hashset< ContainerID > &orphans) override
Definition: flags.hpp:44
Definition: agent.hpp:25
Definition: switchboard.hpp:53
Option< int > stdout_from_fd
Definition: switchboard.hpp:227
Option< int > stderr_to_fd
Definition: switchboard.hpp:230
void run(std::vector< C > &&callbacks, Arguments &&...arguments)
Definition: future.hpp:621
Flags()
Definition: switchboard.hpp:163
Result< Process > process(pid_t pid)
Definition: freebsd.hpp:30
process::Future< Option< mesos::slave::ContainerIO > > extractContainerIO(const ContainerID &containerID)
Definition: none.hpp:27
Definition: attributes.hpp:24
static bool requiresServer(const mesos::slave::ContainerConfig &containerConfig)
process::Future< Nothing > cleanup(const ContainerID &containerId) override
bool unblock(int signal)
Definition: signals.hpp:80
Try< Netlink< struct nl_sock > > socket(int protocol=NETLINK_ROUTE)
Definition: internal.hpp:91
std::string stringify(int flags)
An abstraction around a socket (file descriptor).
Definition: socket.hpp:258
static Try< IOSwitchboard * > create(const Flags &flags, bool local)
Definition: parse.hpp:33
Option< std::string > socket_path
Definition: switchboard.hpp:231
Option< Duration > heartbeat_interval
Definition: switchboard.hpp:233
bool wait_for_connection
Definition: switchboard.hpp:232