blob: acbe948584fa4857d4e34857735d7c0f846d981f [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#!/usr/bin/env python -tt
2#
3# Copyright (c) 2007 Red Hat Inc.
4# Copyright (c) 2009, 2010, 2011 Intel, Inc.
5#
6# This program is free software; you can redistribute it and/or modify it
7# under the terms of the GNU General Public License as published by the Free
8# Software Foundation; version 2 of the License
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13# for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program; if not, write to the Free Software Foundation, Inc., 59
17# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19from __future__ import with_statement
20import os
21import tempfile
22import shutil
23
24from wic import msger
25from wic.utils.errors import CreatorError
26from wic.utils import runner
27
28class BaseImageCreator(object):
29 """Base class for image creation.
30
31 BaseImageCreator is the simplest creator class available; it will
32 create a system image according to the supplied kickstart file.
33
34 e.g.
35
36 import wic.imgcreate as imgcreate
37 ks = imgcreate.read_kickstart("foo.ks")
38 imgcreate.ImageCreator(ks, "foo").create()
39 """
40
41 def __del__(self):
42 self.cleanup()
43
44 def __init__(self, createopts=None):
45 """Initialize an ImageCreator instance.
46
47 ks -- a pykickstart.KickstartParser instance; this instance will be
48 used to drive the install by e.g. providing the list of packages
49 to be installed, the system configuration and %post scripts
50
51 name -- a name for the image; used for e.g. image filenames or
52 filesystem labels
53 """
54
55 self.__builddir = None
56
57 self.ks = None
58 self.name = "target"
59 self.tmpdir = "/var/tmp/wic"
60 self.workdir = "/var/tmp/wic/build"
61
62 # setup tmpfs tmpdir when enabletmpfs is True
63 self.enabletmpfs = False
64
65 if createopts:
66 # Mapping table for variables that have different names.
67 optmap = {"outdir" : "destdir",
68 }
69
70 # update setting from createopts
71 for key in createopts.keys():
72 if key in optmap:
73 option = optmap[key]
74 else:
75 option = key
76 setattr(self, option, createopts[key])
77
78 self.destdir = os.path.abspath(os.path.expanduser(self.destdir))
79
80 self._dep_checks = ["ls", "bash", "cp", "echo"]
81
82 # Output image file names
83 self.outimage = []
84
85 # No ks provided when called by convertor, so skip the dependency check
86 if self.ks:
87 # If we have btrfs partition we need to check necessary tools
88 for part in self.ks.handler.partition.partitions:
89 if part.fstype and part.fstype == "btrfs":
90 self._dep_checks.append("mkfs.btrfs")
91 break
92
93 # make sure the specified tmpdir and cachedir exist
94 if not os.path.exists(self.tmpdir):
95 os.makedirs(self.tmpdir)
96
97
98 #
99 # Hooks for subclasses
100 #
101 def _create(self):
102 """Create partitions for the disk image(s)
103
104 This is the hook where subclasses may create the partitions
105 that will be assembled into disk image(s).
106
107 There is no default implementation.
108 """
109 pass
110
111 def _cleanup(self):
112 """Undo anything performed in _create().
113
114 This is the hook where subclasses must undo anything which was
115 done in _create().
116
117 There is no default implementation.
118
119 """
120 pass
121
122 #
123 # Actual implementation
124 #
125 def __ensure_builddir(self):
126 if not self.__builddir is None:
127 return
128
129 try:
130 self.workdir = os.path.join(self.tmpdir, "build")
131 if not os.path.exists(self.workdir):
132 os.makedirs(self.workdir)
133 self.__builddir = tempfile.mkdtemp(dir=self.workdir,
134 prefix="imgcreate-")
135 except OSError as err:
136 raise CreatorError("Failed create build directory in %s: %s" %
137 (self.tmpdir, err))
138
139 def __setup_tmpdir(self):
140 if not self.enabletmpfs:
141 return
142
143 runner.show('mount -t tmpfs -o size=4G tmpfs %s' % self.workdir)
144
145 def __clean_tmpdir(self):
146 if not self.enabletmpfs:
147 return
148
149 runner.show('umount -l %s' % self.workdir)
150
151 def create(self):
152 """Create partitions for the disk image(s)
153
154 Create the partitions that will be assembled into disk
155 image(s).
156 """
157 self.__setup_tmpdir()
158 self.__ensure_builddir()
159
160 self._create()
161
162 def cleanup(self):
163 """Undo anything performed in create().
164
165 Note, make sure to call this method once finished with the creator
166 instance in order to ensure no stale files are left on the host e.g.:
167
168 creator = ImageCreator(ks, name)
169 try:
170 creator.create()
171 finally:
172 creator.cleanup()
173
174 """
175 if not self.__builddir:
176 return
177
178 self._cleanup()
179
180 shutil.rmtree(self.__builddir, ignore_errors=True)
181 self.__builddir = None
182
183 self.__clean_tmpdir()
184
185
186 def print_outimage_info(self):
187 msg = "The new image can be found here:\n"
188 self.outimage.sort()
189 for path in self.outimage:
190 msg += ' %s\n' % os.path.abspath(path)
191
192 msger.info(msg)