summaryrefslogtreecommitdiff
path: root/cloudinit/distros/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit/distros/__init__.py')
-rw-r--r--cloudinit/distros/__init__.py163
1 files changed, 163 insertions, 0 deletions
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
new file mode 100644
index 00000000..da4d0180
--- /dev/null
+++ b/cloudinit/distros/__init__.py
@@ -0,0 +1,163 @@
+# vi: ts=4 expandtab
+#
+# Copyright (C) 2012 Canonical Ltd.
+# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
+# Copyright (C) 2012 Yahoo! Inc.
+#
+# Author: Scott Moser <scott.moser@canonical.com>
+# Author: Juerg Haefliger <juerg.haefliger@hp.com>
+# Author: Joshua Harlow <harlowja@yahoo-inc.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from StringIO import StringIO
+
+import abc
+
+from cloudinit import importer
+from cloudinit import log as logging
+from cloudinit import util
+
+# TODO: Make this via config??
+IFACE_ACTIONS = {
+ 'up': ['ifup', '--all'],
+ 'down': ['ifdown', '--all'],
+}
+
+LOG = logging.getLogger(__name__)
+
+
+class Distro(object):
+
+ __metaclass__ = abc.ABCMeta
+
+ def __init__(self, name, cfg, paths):
+ self._paths = paths
+ self._cfg = cfg
+ self.name = name
+
+ @abc.abstractmethod
+ def install_packages(self, pkglist):
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def _write_network(self, settings):
+ # In the future use the http://fedorahosted.org/netcf/
+ # to write this blob out in a distro format
+ raise NotImplementedError()
+
+ def get_option(self, opt_name, default=None):
+ return self._cfg.get(opt_name, default)
+
+ @abc.abstractmethod
+ def set_hostname(self, hostname):
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def update_hostname(self, hostname, prev_hostname_fn):
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def package_command(self, cmd, args=None):
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def update_package_sources(self):
+ raise NotImplementedError()
+
+ def get_package_mirror(self):
+ return self.get_option('package_mirror')
+
+ def apply_network(self, settings, bring_up=True):
+ # Write it out
+ self._write_network(settings)
+ # Now try to bring them up
+ if bring_up:
+ return self._interface_action('up')
+ return False
+
+ @abc.abstractmethod
+ def apply_locale(self, locale, out_fn=None):
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def set_timezone(self, tz):
+ raise NotImplementedError()
+
+ def _get_localhost_ip(self):
+ return "127.0.0.1"
+
+ def update_etc_hosts(self, hostname, fqdn):
+ # Format defined at
+ # http://unixhelp.ed.ac.uk/CGI/man-cgi?hosts
+ header = "# Added by cloud-init"
+ real_header = "%s on %s" % (header, util.time_rfc2822())
+ local_ip = self._get_localhost_ip()
+ hosts_line = "%s\t%s %s" % (local_ip, fqdn, hostname)
+ new_etchosts = StringIO()
+ need_write = False
+ need_change = True
+ hosts_ro_fn = self._paths.join(True, "/etc/hosts")
+ for line in util.load_file(hosts_ro_fn).splitlines():
+ if line.strip().startswith(header):
+ continue
+ if not line.strip() or line.strip().startswith("#"):
+ new_etchosts.write("%s\n" % (line))
+ continue
+ split_line = [s.strip() for s in line.split()]
+ if len(split_line) < 2:
+ new_etchosts.write("%s\n" % (line))
+ continue
+ (ip, hosts) = split_line[0], split_line[1:]
+ if ip == local_ip:
+ if sorted([hostname, fqdn]) == sorted(hosts):
+ need_change = False
+ if need_change:
+ line = "%s\n%s" % (real_header, hosts_line)
+ need_change = False
+ need_write = True
+ new_etchosts.write("%s\n" % (line))
+ if need_change:
+ new_etchosts.write("%s\n%s\n" % (real_header, hosts_line))
+ need_write = True
+ if need_write:
+ contents = new_etchosts.getvalue()
+ util.write_file(self._paths.join(False, "/etc/hosts"),
+ contents, mode=0644)
+
+ def _interface_action(self, action):
+ if action not in IFACE_ACTIONS:
+ raise NotImplementedError("Unknown interface action %s" % (action))
+ cmd = IFACE_ACTIONS[action]
+ try:
+ LOG.debug("Attempting to run %s interface action using command %s",
+ action, cmd)
+ (_out, err) = util.subp(cmd)
+ if len(err):
+ LOG.warn("Running %s resulted in stderr output: %s", cmd, err)
+ return True
+ except util.ProcessExecutionError:
+ util.logexc(LOG, "Running interface command %s failed", cmd)
+ return False
+
+
+def fetch(name):
+ locs = importer.find_module(name,
+ ['', __name__],
+ ['Distro'])
+ if not locs:
+ raise ImportError("No distribution found for distro %s"
+ % (name))
+ mod = importer.import_module(locs[0])
+ cls = getattr(mod, 'Distro')
+ return cls