3 # Copyright 2012 GRNET S.A. All rights reserved.
5 # Redistribution and use in source and binary forms, with or
6 # without modification, are permitted provided that the following
9 # 1. Redistributions of source code must retain the above
10 # copyright notice, this list of conditions and the following
13 # 2. Redistributions in binary form must reproduce the above
14 # copyright notice, this list of conditions and the following
15 # disclaimer in the documentation and/or other materials
16 # provided with the distribution.
18 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 # POSSIBILITY OF SUCH DAMAGE.
31 # The views and conclusions contained in the software and
32 # documentation are those of the authors and should not be
33 # interpreted as representing official policies, either expressed
34 # or implied, of GRNET S.A.
42 from image_creator import __version__ as version
43 from image_creator.util import FatalError, MD5
44 from image_creator.output.dialog import InitializationOutput
45 from image_creator.disk import Disk
46 from image_creator.os_type import os_cls
53 class Reset(Exception):
57 def confirm_exit(d, msg=''):
58 return not d.yesno("%s Do you want to exit?" % msg, width=YESNO_WIDTH)
63 "Are you sure you want to reset everything?",
67 def upload_image(session):
70 if "account" not in session:
71 d.msgbox("You need to provide your ~okeanos login username before you "
72 "can upload images to pithos+", width=MSGBOX_WIDTH)
75 if "token" not in session:
76 d.msgbox("You need to provide your ~okeanos account authentication "
77 "token before you can upload images to pithos+",
82 (code, answer) = d.inputbox("Please provide a filename:",
83 init=session["upload"] if "upload" in session else '')
84 if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
87 answer = answer.strip()
89 d.msgbox("Filename cannot be empty", width=MSGBOX_WIDTH)
92 session["upload"] = answer
96 def register_image(session):
99 if "account" not in session:
100 d.msgbox("You need to provide your ~okeanos login username before you "
101 "can register an images to cyclades",
105 if "token" not in session:
106 d.msgbox("You need to provide your ~okeanos account authentication "
107 "token before you can register an images to cyclades",
111 if "upload" not in session:
112 d.msgbox("You need to have an image uploaded to pithos+ before you "
113 "can register it to cyclades",
120 def kamaki_menu(session):
121 d = session['dialog']
122 default_item = "Account"
124 account = session["account"] if "account" in session else "<none>"
125 token = session["token"] if "token" in session else "<none>"
126 upload = session["upload"] if "upload" in session else "<none>"
127 (code, choice) = d.menu(
128 "Choose one of the following or press <Back> to go back.",
130 choices=[("Account", "Change your ~okeanos username: %s" %
132 ("Token", "Change your ~okeanos token: %s" %
134 ("Upload", "Upload image to pithos+"),
135 ("Register", "Register image to cyclades: %s" % upload)],
137 default_item=default_item,
138 title="Image Registration Menu")
140 if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
143 if choice == "Account":
144 default_item = "Account"
145 (code, answer) = d.inputbox(
146 "Please provide your ~okeanos account e-mail address:",
147 init=session["account"] if "account" in session else '',
149 if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
151 if len(answer) == 0 and "account" in session:
152 del session["account"]
154 session["account"] = answer.strip()
155 default_item = "Token"
156 elif choice == "Token":
157 default_item = "Token"
158 (code, answer) = d.inputbox(
159 "Please provide your ~okeanos account authetication token:",
160 init=session["token"] if "token" in session else '',
162 if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
164 if len(answer) == 0 and "token" in session:
167 session["token"] = answer.strip()
168 default_item = "Upload"
169 elif choice == "Upload":
170 if upload_image(session):
171 default_item = "Register"
173 default_item = "Upload"
174 elif choice == "Register":
175 if register_image(session):
178 default_item = "Register"
181 def main_menu(session):
182 d = session['dialog']
183 dev = session['device']
184 d.setBackgroundTitle("OS: %s, Distro: %s" % (dev.ostype, dev.distro))
185 actions = {"Register": kamaki_menu}
186 default_item = "Customize"
189 (code, choice) = d.menu(
190 "Choose one of the following or press <Exit> to exit.",
192 choices=[("Customize", "Run various image customization tasks"),
193 ("Deploy", "Configure ~okeanos image deployment options"),
194 ("Register", "Register image to ~okeanos"),
195 ("Extract", "Dump image to local file system"),
196 ("Reset", "Reset everything and start over again"),
197 ("Help", "Get help for using snf-image-creator")],
199 default_item=default_item,
200 title="Image Creator for ~okeanos (snf-image-creator version %s)" %
203 if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
209 if choice == "Reset":
211 d.infobox("Resetting snf-image-creator. Please wait...")
215 elif choice in actions:
216 actions[choice](session)
222 (code, path) = d.fselect(root, 10, 50,
223 title="Please select input media")
224 if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
225 if confirm_exit(d, "You canceled the media selection dialog box."):
230 if not os.path.exists(path):
231 d.msgbox("The file you choose does not exist", width=MSGBOX_WIDTH)
239 def collect_metadata(dev, out):
241 dev.mount(readonly=True)
242 out.output("Collecting image metadata...")
243 cls = os_cls(dev.distro, dev.ostype)
244 image_os = cls(dev.root, dev.g, out)
251 def image_creator(d):
252 basename = os.path.basename(sys.argv[0])
253 usage = "Usage: %s [input_media]" % basename
254 if len(sys.argv) > 2:
255 sys.stderr.write("%s\n" % usage)
258 if os.geteuid() != 0:
259 raise FatalError("You must run %s as root" % basename)
261 media = sys.argv[1] if len(sys.argv) == 2 else select_file(d)
263 out = InitializationOutput(d)
264 disk = Disk(media, out)
266 def signal_handler(signum, fram):
270 signal.signal(signal.SIGINT, signal_handler)
272 snapshot = disk.snapshot()
273 dev = disk.get_device(snapshot)
275 metadata = collect_metadata(dev, out)
278 # Make sure the signal handler does not call out.cleanup again
281 instancemethod = type(InitializationOutput.cleanup)
282 out.cleanup = instancemethod(dummy, out, InitializationOutput)
284 session = {"dialog": d,
287 "metadata": metadata}
290 d.infobox("Thank you for using snf-image-creator. Bye", width=53)
299 d = dialog.Dialog(dialog="dialog")
304 ret = image_creator(d)
306 except FatalError as e:
307 msg = textwrap.fill(str(e), width=70)
308 d.infobox(msg, width=70, title="Fatal Error")
313 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :