Apache Mesos
port_mapper.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 __NETWORK_CNI_PLUGIN_PORTMAPPER_HPP__
18 #define __NETWORK_CNI_PLUGIN_PORTMAPPER_HPP__
19 
20 #include <map>
21 #include <string>
22 
23 #include <stout/json.hpp>
24 #include <stout/option.hpp>
25 
26 #include <process/future.hpp>
27 #include <process/owned.hpp>
28 #include <process/process.hpp>
29 
30 #include <mesos/mesos.hpp>
31 
33 
34 namespace mesos {
35 namespace internal {
36 namespace slave {
37 namespace cni {
38 
40 {
41 public:
42  // Error codes for the port mapper plugin.
43  // NOTE: Plugin specific erros should use Values of 100+.
44  static constexpr int ERROR_READ_FAILURE = 100; // Fail to read from stdin.
45  static constexpr int ERROR_BAD_ARGS = 101; // Miss or invalid arguments.
46  static constexpr int ERROR_DELEGATE_FAILURE = 102;
47  static constexpr int ERROR_PORTMAP_FAILURE = 103;
48  static constexpr int ERROR_UNSUPPORTED_COMMAND = 104;
49 
50  // Takes in a JSON formatted string, validates that the following
51  // fields are present:
52  // * 'name' : Name of the CNI configuration that will be passed
53  // to the CNI plugin used for delegation.
54  // * 'chain' : The iptables chain to use for setting up DNAT.
55  // * 'delegate': The port-mapper should always be used in
56  // conjunction with another CNI plugin that sets up
57  // the interfaces and IP address on the container.
58  // This field holds the CNI configuration of the
59  // plugin to which the port-mapper delegates the
60  // functionality of connecting the container to the
61  // network.
62  // * 'args' : The port-mapper uses the `NetworkInfo` passed by
63  // Mesos as meta-data in the "args" field to decipher
64  // the ports for which DNAT needs to bet setup. To
65  // understand how Mesos uses this field please read
66  // the documentation for "CNI support in Mesos":
67  // http://mesos.apache.org/documentation/latest/cni/
68  //
69  // In case of an error returns a JSON formatted string of type
70  // `spec::Error` as the error message for the `Try`.
72  const std::string& cniConfig);
73 
74  // Executes the CNI plugin specified in 'delegate'. When
75  // `cniCommand` is set to `spec::CNI_CMD_ADD` successful execution
76  // of the 'delegate' plugin will install port-forwarding rules, if
77  // any, that are specified in `NetworkInfo`. On success will return
78  // a JSON string seen in the successful execution of the 'delegate'
79  // plugin. When `cniCommand` is set to `spec::CNI_CMD_DEL`
80  // successful execution of the delegate plugin will return `None`.
82 
83  virtual ~PortMapper() {};
84 
85 protected:
86  // Used to invoke the plugin specified in 'delegate'. The possible
87  // values for `command` are `spec::CNI_CMD_ADD` or
88  // `spec::CNI_CMD_DEL`. The `command` is used in
89  // setting the CNI_COMMAND environment variable before invoking the
90  // 'delegate' plugin.
91  //
92  // When `command` is set to `spec::CNI_CMD_ADD` returns a
93  // `spec::NetworkInfo` on successful execution of the 'delegate'
94  // plugin. When command is set to `spec::CNI_CMD_DEL` returns `None`
95  // on successful execution of the plugin.
96  //
97  // NOTE: Defining `delegate` as a virtual method so that we can mock it.
98  virtual Result<spec::NetworkInfo> delegate(const std::string& command);
99 
100 private:
101  PortMapper(
102  const std::string& _cniCommand, // ADD, DEL or VERSION.
103  const std::string& _cniContainerId, // Container ID.
104  const std::string& _cniNetNs, // Path to network namespace file.
105  const std::string& _cniIfName, // Interface name to set up.
106  const Option<std::string>& _cniArgs, // Extra arguments.
107  const std::string& _cniPath, // Paths to search for CNI plugins.
108  const mesos::NetworkInfo& _networkInfo,
109  const std::string& _delegatePlugin,
110  const JSON::Object& _delegateConfig,
111  const std::string& _chain,
112  const std::vector<std::string>& _excludeDevices)
113  : cniCommand(_cniCommand),
114  cniContainerId(_cniContainerId),
115  cniNetNs(_cniNetNs),
116  cniIfName(_cniIfName),
117  cniArgs(_cniArgs),
118  cniPath(_cniPath),
119  networkInfo(_networkInfo),
120  delegatePlugin(_delegatePlugin),
121  delegateConfig(_delegateConfig),
122  chain(_chain),
123  excludeDevices(_excludeDevices){};
124 
125  // Returns a tag that will be appended to every DNAT rule in the
126  // iptables associated with this container. Currently the tag is of
127  // the form: 'container_id: <CNI_CONTAINERID>'.
128  std::string getIptablesRuleTag();
129 
130  std::string getIptablesRule(
131  const net::IP& ip,
132  const mesos::NetworkInfo::PortMapping& portMapping);
133 
134  Try<Nothing> addPortMapping(
135  const net::IP& ip,
136  const mesos::NetworkInfo::PortMapping& portMapping);
137 
138  Try<Nothing> delPortMapping();
139 
140  Try<std::string, spec::PluginError> handleAddCommand();
141  Try<Nothing, spec::PluginError> handleDelCommand();
142 
143  const std::string cniCommand;
144  const std::string cniContainerId;
145  const std::string cniNetNs;
146  const std::string cniIfName;
147  const Option<std::string> cniArgs;
148  const std::string cniPath;
149 
150  const mesos::NetworkInfo networkInfo;
151 
152  const std::string delegatePlugin;
153  const JSON::Object delegateConfig;
154 
155  // The iptable chain to which the DNAT rules need to be added. We
156  // need a separate chain, so that we can group the DNAT rules
157  // specific to this CNI network under this chain. It makes it easier
158  // for the operator to analyze the ownership of these rules if they
159  // are grouped under a chain that the operator is aware is used by
160  // the CNI plugin.
161  const std::string chain;
162 
163  // List of ingress devices that should be excluded from the DNAT
164  // rules.
165  const std::vector<std::string> excludeDevices;
166 };
167 
168 } // namespace cni {
169 } // namespace slave {
170 } // namespace internal {
171 } // namespace mesos {
172 
173 #endif // __NETWORK_CNI_PLUGIN_PORTMAPPER_HPP__
static Try< process::Owned< PortMapper >, spec::PluginError > create(const std::string &cniConfig)
Definition: check.hpp:33
virtual ~PortMapper()
Definition: port_mapper.hpp:83
Definition: check.hpp:30
static constexpr int ERROR_PORTMAP_FAILURE
Definition: port_mapper.hpp:47
Definition: json.hpp:158
Definition: ip.hpp:73
static constexpr int ERROR_DELEGATE_FAILURE
Definition: port_mapper.hpp:46
static constexpr int ERROR_BAD_ARGS
Definition: port_mapper.hpp:45
Definition: spec.hpp:26
Try< Option< std::string >, spec::PluginError > execute()
Definition: attributes.hpp:24
static constexpr int ERROR_UNSUPPORTED_COMMAND
Definition: port_mapper.hpp:48
virtual Result< spec::NetworkInfo > delegate(const std::string &command)
Definition: port_mapper.hpp:39
static constexpr int ERROR_READ_FAILURE
Definition: port_mapper.hpp:44