softwarecontainer  0.18.0-739e8d7 2017-05-04
main.cpp
1 /*
2  * Copyright (C) 2016-2017 Pelagicore AB
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
9  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
11  * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
12  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
13  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
14  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15  * SOFTWARE.
16  *
17  * For further information see LICENSE
18  */
19 
20 
21 #include <glibmm/optioncontext.h>
22 
23 #include "config/config.h"
24 #include "config/configerror.h"
25 #include "config/configloader.h"
26 #include "config/fileconfigloader.h"
27 #include "config/commandlineconfigsource.h"
28 #include "config/mainconfigsource.h"
29 #include "config/defaultconfigsource.h"
30 #include "config/configsource.h"
31 #include "config/configitem.h"
32 #include "config/configdefinition.h"
33 
34 #include "dbus/softwarecontaineragentadaptor.h"
35 
36 namespace softwarecontainer {
37 
38 LOG_DEFINE_APP_IDS("SCAG", "SoftwareContainer agent");
39 LOG_DECLARE_DEFAULT_CONTEXT(PAM_DefaultLogContext, "MAIN", "Main context");
40 
41 } // namespace softwarecontainer
42 
43 using namespace softwarecontainer;
44 
45 /*
46  * When we get signals that can be trapped, we want the main loop to be quitted.
47  */
48 int signalHandler(void *data) {
49  log_debug() << "Caught signal, exiting!";
50  Glib::RefPtr<Glib::MainLoop> *ml = static_cast<Glib::RefPtr<Glib::MainLoop> *>(data);
51  (*ml)->quit();
52  return 0;
53 }
54 
55 
56 int main(int argc, char **argv)
57 {
58  // Config file path default 'SC_CONFIG_FILE' shuld be set by the build system
59  Glib::OptionEntry configOpt;
60  configOpt.set_long_name("config");
61  configOpt.set_short_name('c');
62  configOpt.set_arg_description("<path>");
63  configOpt.set_description("Path to SoftwareContainer configuration file,"
64  " defaults to \"" + std::string(SC_CONFIG_FILE) + "\"");
65 
66  Glib::OptionEntry userOpt;
67  userOpt.set_long_name("user");
68  userOpt.set_short_name('u');
69  userOpt.set_arg_description("<uid>");
70  userOpt.set_description("Default user id to be used when starting processes in the container,"
71  " defaults to 0");
72 
73  Glib::OptionEntry timeoutOpt;
74  timeoutOpt.set_long_name("timeout");
75  timeoutOpt.set_short_name('t');
76  timeoutOpt.set_arg_description("<seconds>");
77  timeoutOpt.set_description("Timeout in seconds to wait for containers to shutdown,"
78  " defaults to " + std::to_string(SC_SHUTDOWN_TIMEOUT));
79 
80  Glib::OptionEntry serviceManifestDirOpt;
81  serviceManifestDirOpt.set_long_name("manifest-dir");
82  serviceManifestDirOpt.set_short_name('m');
83  serviceManifestDirOpt.set_arg_description("<filepath>");
84  serviceManifestDirOpt.set_description("Path to a file or directory where service manifest(s) "
85  "exist, defaults to \""
86  + std::string(SC_SERVICE_MANIFEST_DIR) + "\"");
87 
88  Glib::OptionEntry defaultServiceManifestDirOpt;
89  defaultServiceManifestDirOpt.set_long_name("default-manifest-dir");
90  defaultServiceManifestDirOpt.set_short_name('d');
91  defaultServiceManifestDirOpt.set_arg_description("<filepath>");
92  defaultServiceManifestDirOpt.set_description("Path to a file or directory where default "
93  "service manifest(s) exist, defaults to \""
94  + std::string(SC_DEFAULT_SERVICE_MANIFEST_DIR) + "\"");
95 
96  Glib::OptionEntry sessionBusOpt;
97  sessionBusOpt.set_long_name("session-bus");
98  sessionBusOpt.set_short_name('b');
99  sessionBusOpt.set_description("Use the session bus instead of the system bus, "
100  "defaults to " + std::string(SC_USE_SESSION_BUS ? "true" : "false"));
101 
102 
103  /* Default values need to be somehting that should not be set explicitly
104  * by the user. */
105 
106  std::string configPath = ConfigDefinition::SC_CONFIG_PATH_INITIAL_VALUE;
107  int userID = 0;
108  int timeout = ConfigDefinition::SHUTDOWN_TIMEOUT_INITIAL_VALUE;
109  std::string serviceManifestDir = ConfigDefinition::SERVICE_MANIFEST_DIR_INITIAL_VALUE;
110  std::string defaultServiceManifestDir = ConfigDefinition::DEFAULT_SERVICE_MANIFEST_DIR_INITIAL_VALUE;
111  bool useSessionBus = ConfigDefinition::USE_SESSION_BUS_INITIAL_VALUE;
112 
113  Glib::OptionGroup mainGroup("Options", "Options for SoftwareContainer");
114 
115  mainGroup.add_entry_filename(configOpt, configPath);
116  mainGroup.add_entry(userOpt, userID);
117 
118  mainGroup.add_entry(timeoutOpt, timeout);
119  mainGroup.add_entry_filename(serviceManifestDirOpt, serviceManifestDir);
120  mainGroup.add_entry_filename(defaultServiceManifestDirOpt, defaultServiceManifestDir);
121  mainGroup.add_entry(sessionBusOpt, useSessionBus);
122 
123  Glib::OptionContext optionContext;
124  optionContext.set_help_enabled(true); // Automatic --help
125  optionContext.set_ignore_unknown_options(false);
126  optionContext.set_summary("SoftwareContainer Agent v" + std::string(PACKAGE_VERSION));
127  optionContext.set_description("Documentation is available at http://pelagicore.github.io/softwarecontainer");
128  optionContext.set_main_group(mainGroup);
129 
130  try {
131  optionContext.parse(argc, argv);
132  } catch (Glib::OptionError &err) {
133  log_error() << err.what();
134  exit(1);
135  }
136 
137  profilepoint("softwareContainerStart");
138  log_debug() << "Starting softwarecontainer agent";
139 
140  Glib::init();
141  Gio::init();
142 
143  Glib::RefPtr<Glib::MainContext> mainContext = Glib::MainContext::get_default();
144  Glib::RefPtr<Glib::MainLoop> ml = Glib::MainLoop::create(mainContext);
145 
146  // Config file set on commandline should take precedence over default
147  std::string configFileLocation;
148  if (configPath != ConfigDefinition::SC_CONFIG_PATH_INITIAL_VALUE) {
149  configFileLocation = configPath;
150  } else {
151  configFileLocation = std::string(SC_CONFIG_FILE /* defined by CMake*/);
152  }
153 
154  /*
155  * Put all commandline options in lists to be passed to the commandline config source
156  */
157  std::vector<StringConfig> stringConfigs = std::vector<StringConfig>();
158  if (serviceManifestDir != ConfigDefinition::SERVICE_MANIFEST_DIR_INITIAL_VALUE) {
159  if ('/' != serviceManifestDir.back()) {
160  serviceManifestDir.push_back('/');
161  }
162 
163  StringConfig config(ConfigDefinition::SC_GROUP,
164  ConfigDefinition::SC_SERVICE_MANIFEST_DIR_KEY,
165  serviceManifestDir);
166  stringConfigs.push_back(config);
167  }
168  if (defaultServiceManifestDir != ConfigDefinition::DEFAULT_SERVICE_MANIFEST_DIR_INITIAL_VALUE) {
169  if ('/' != defaultServiceManifestDir.back()) {
170  defaultServiceManifestDir.push_back('/');
171  }
172 
173  StringConfig config(ConfigDefinition::SC_GROUP,
174  ConfigDefinition::SC_DEFAULT_SERVICE_MANIFEST_DIR_KEY,
175  defaultServiceManifestDir);
176  stringConfigs.push_back(config);
177  }
178 
179  std::vector<IntConfig> intConfigs = std::vector<IntConfig>();
180  if (timeout != ConfigDefinition::SHUTDOWN_TIMEOUT_INITIAL_VALUE) {
181  IntConfig config(ConfigDefinition::SC_GROUP,
182  ConfigDefinition::SC_SHUTDOWN_TIMEOUT_KEY,
183  timeout);
184  intConfigs.push_back(config);
185  }
186 
187  std::vector<BoolConfig> boolConfigs = std::vector<BoolConfig>();
188  /* The bool options should be on/off flags so if they were set they are 'true'
189  * otherwise they are still the default 'false' set above. */
190  if (useSessionBus == true) {
191  BoolConfig config(ConfigDefinition::SC_GROUP,
192  ConfigDefinition::SC_USE_SESSION_BUS_KEY,
193  useSessionBus);
194  boolConfigs.push_back(config);
195  }
196 
197  try {
198  // Create a config source representing the commandline options
199  std::unique_ptr<ConfigSource> cmdlineConfigs(new CommandlineConfigSource(stringConfigs,
200  intConfigs,
201  boolConfigs));
202 
203  // Create a config source representing the main config file
204  std::unique_ptr<ConfigLoader> loader(new FileConfigLoader(configFileLocation));
205  std::unique_ptr<ConfigSource> mainConfigs(new MainConfigSource(std::move(loader),
206  ConfigDefinition::typeMap()));
207 
208  // Create a config source representing the default values
209  std::unique_ptr<ConfigSource> defaultConfigs(new DefaultConfigSource());
210 
211  std::vector<std::unique_ptr<ConfigSource>> configSources;
212  configSources.push_back(std::move(cmdlineConfigs));
213  configSources.push_back(std::move(mainConfigs));
214  configSources.push_back(std::move(defaultConfigs));
215 
216  std::shared_ptr<Config> config = std::make_shared<Config>(std::move(configSources),
217  ConfigDefinition::mandatory(),
218  ConfigDependencies());
219  auto factory = std::make_shared<SoftwareContainerFactory>();
220  auto utility = std::make_shared<ContainerUtilityInterface>(config);
221 
222  // Create the actual agent
223  ::softwarecontainer::SoftwareContainerAgent agent(mainContext, config, factory, utility);
224 
225  // We may have had a value for this in the config, so we need to check it, to know
226  // what bus we want to connect to on D-Bus.
227  useSessionBus = config->getBoolValue(ConfigDefinition::SC_GROUP,
228  ConfigDefinition::SC_USE_SESSION_BUS_KEY);
229 
230  // Create the agent adaptor, that connects the agent to D-Bus.
231  std::unique_ptr<SoftwareContainerAgentAdaptor> adaptor(
232  // The adaptor needs access to the mainloop in order to be able to exit the
233  // loop in case dbus setup fails.
234  new SoftwareContainerAgentAdaptor(ml, agent, useSessionBus)
235  );
236 
237  // Register UNIX signal handler
238  g_unix_signal_add(SIGINT, &signalHandler, &ml);
239  g_unix_signal_add(SIGTERM, &signalHandler, &ml);
240  ml->run();
241 
242  log_debug() << "Exiting softwarecontainer agent";
243  return 0;
244  } catch (SoftwareContainerError &error) {
245  log_error() << std::string(error.what());
246  return 1;
247  }
248 }
Represents a config item of type bool.
Definition: configitem.h:72
Represents a config item of type string.
Definition: configitem.h:46
Represents the default config values.
A config source representing the commandline options.
Developers guide to adding a config item:
Represents a config item of type int.
Definition: configitem.h:59