Statistics
| Branch: | Tag: | Revision:

root / image_creator / dialog_menu.py @ 34e7a04a

History | View | Annotate | Download (29.1 kB)

1 121f3bc0 Nikos Skalkotos
# -*- coding: utf-8 -*-
2 121f3bc0 Nikos Skalkotos
#
3 023e1217 Nikos Skalkotos
# Copyright 2012 GRNET S.A. All rights reserved.
4 023e1217 Nikos Skalkotos
#
5 023e1217 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
6 023e1217 Nikos Skalkotos
# without modification, are permitted provided that the following
7 023e1217 Nikos Skalkotos
# conditions are met:
8 023e1217 Nikos Skalkotos
#
9 023e1217 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
10 023e1217 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
11 023e1217 Nikos Skalkotos
#      disclaimer.
12 023e1217 Nikos Skalkotos
#
13 023e1217 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
14 023e1217 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
15 023e1217 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
16 023e1217 Nikos Skalkotos
#      provided with the distribution.
17 023e1217 Nikos Skalkotos
#
18 023e1217 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 023e1217 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 023e1217 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 023e1217 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 023e1217 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 023e1217 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 023e1217 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 023e1217 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 023e1217 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 023e1217 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 023e1217 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 023e1217 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
30 023e1217 Nikos Skalkotos
#
31 023e1217 Nikos Skalkotos
# The views and conclusions contained in the software and
32 023e1217 Nikos Skalkotos
# documentation are those of the authors and should not be
33 023e1217 Nikos Skalkotos
# interpreted as representing official policies, either expressed
34 023e1217 Nikos Skalkotos
# or implied, of GRNET S.A.
35 023e1217 Nikos Skalkotos
36 121f3bc0 Nikos Skalkotos
"""This module implements the "expert" mode of the dialog-based version of
37 121f3bc0 Nikos Skalkotos
snf-image-creator.
38 121f3bc0 Nikos Skalkotos
"""
39 121f3bc0 Nikos Skalkotos
40 023e1217 Nikos Skalkotos
import os
41 023e1217 Nikos Skalkotos
import textwrap
42 023e1217 Nikos Skalkotos
import StringIO
43 8e58e699 Nikos Skalkotos
import json
44 023e1217 Nikos Skalkotos
45 023e1217 Nikos Skalkotos
from image_creator import __version__ as version
46 71b0ab28 Nikos Skalkotos
from image_creator.util import MD5, FatalError
47 023e1217 Nikos Skalkotos
from image_creator.output.dialog import GaugeOutput, InfoBoxOutput
48 023e1217 Nikos Skalkotos
from image_creator.kamaki_wrapper import Kamaki, ClientError
49 023e1217 Nikos Skalkotos
from image_creator.help import get_help_file
50 023e1217 Nikos Skalkotos
from image_creator.dialog_util import SMALL_WIDTH, WIDTH, \
51 0a116b9d Nikos Skalkotos
    update_background_title, confirm_reset, confirm_exit, Reset, \
52 49c07ce3 Nikos Skalkotos
    extract_image, extract_metadata_string, add_cloud, edit_cloud
53 023e1217 Nikos Skalkotos
54 023e1217 Nikos Skalkotos
CONFIGURATION_TASKS = [
55 023e1217 Nikos Skalkotos
    ("Partition table manipulation", ["FixPartitionTable"],
56 023e1217 Nikos Skalkotos
        ["linux", "windows"]),
57 023e1217 Nikos Skalkotos
    ("File system resize",
58 023e1217 Nikos Skalkotos
        ["FilesystemResizeUnmounted", "FilesystemResizeMounted"],
59 023e1217 Nikos Skalkotos
        ["linux", "windows"]),
60 023e1217 Nikos Skalkotos
    ("Swap partition configuration", ["AddSwap"], ["linux"]),
61 023e1217 Nikos Skalkotos
    ("SSH keys removal", ["DeleteSSHKeys"], ["linux"]),
62 023e1217 Nikos Skalkotos
    ("Temporal RDP disabling", ["DisableRemoteDesktopConnections"],
63 023e1217 Nikos Skalkotos
        ["windows"]),
64 023e1217 Nikos Skalkotos
    ("SELinux relabeling at next boot", ["SELinuxAutorelabel"], ["linux"]),
65 023e1217 Nikos Skalkotos
    ("Hostname/Computer Name assignment", ["AssignHostname"],
66 023e1217 Nikos Skalkotos
        ["windows", "linux"]),
67 023e1217 Nikos Skalkotos
    ("Password change", ["ChangePassword"], ["windows", "linux"]),
68 023e1217 Nikos Skalkotos
    ("File injection", ["EnforcePersonality"], ["windows", "linux"])
69 023e1217 Nikos Skalkotos
]
70 023e1217 Nikos Skalkotos
71 023e1217 Nikos Skalkotos
72 61d14323 Nikos Skalkotos
class MetadataMonitor(object):
73 88f83027 Nikos Skalkotos
    """Monitors image metadata chages"""
74 023e1217 Nikos Skalkotos
    def __init__(self, session, meta):
75 023e1217 Nikos Skalkotos
        self.session = session
76 023e1217 Nikos Skalkotos
        self.meta = meta
77 023e1217 Nikos Skalkotos
78 023e1217 Nikos Skalkotos
    def __enter__(self):
79 023e1217 Nikos Skalkotos
        self.old = {}
80 023e1217 Nikos Skalkotos
        for (k, v) in self.meta.items():
81 023e1217 Nikos Skalkotos
            self.old[k] = v
82 023e1217 Nikos Skalkotos
83 023e1217 Nikos Skalkotos
    def __exit__(self, type, value, traceback):
84 023e1217 Nikos Skalkotos
        d = self.session['dialog']
85 023e1217 Nikos Skalkotos
86 023e1217 Nikos Skalkotos
        altered = {}
87 023e1217 Nikos Skalkotos
        added = {}
88 023e1217 Nikos Skalkotos
89 023e1217 Nikos Skalkotos
        for (k, v) in self.meta.items():
90 023e1217 Nikos Skalkotos
            if k not in self.old:
91 023e1217 Nikos Skalkotos
                added[k] = v
92 023e1217 Nikos Skalkotos
            elif self.old[k] != v:
93 023e1217 Nikos Skalkotos
                altered[k] = v
94 023e1217 Nikos Skalkotos
95 023e1217 Nikos Skalkotos
        if not (len(added) or len(altered)):
96 023e1217 Nikos Skalkotos
            return
97 023e1217 Nikos Skalkotos
98 023e1217 Nikos Skalkotos
        msg = "The last action has changed some image properties:\n\n"
99 023e1217 Nikos Skalkotos
        if len(added):
100 023e1217 Nikos Skalkotos
            msg += "New image properties:\n"
101 023e1217 Nikos Skalkotos
            for (k, v) in added.items():
102 023e1217 Nikos Skalkotos
                msg += '    %s: "%s"\n' % (k, v)
103 023e1217 Nikos Skalkotos
            msg += "\n"
104 023e1217 Nikos Skalkotos
        if len(altered):
105 023e1217 Nikos Skalkotos
            msg += "Updated image properties:\n"
106 023e1217 Nikos Skalkotos
            for (k, v) in altered.items():
107 023e1217 Nikos Skalkotos
                msg += '    %s: "%s" -> "%s"\n' % (k, self.old[k], v)
108 023e1217 Nikos Skalkotos
            msg += "\n"
109 023e1217 Nikos Skalkotos
110 023e1217 Nikos Skalkotos
        self.session['metadata'].update(added)
111 023e1217 Nikos Skalkotos
        self.session['metadata'].update(altered)
112 023e1217 Nikos Skalkotos
        d.msgbox(msg, title="Image Property Changes", width=SMALL_WIDTH)
113 023e1217 Nikos Skalkotos
114 023e1217 Nikos Skalkotos
115 023e1217 Nikos Skalkotos
def upload_image(session):
116 ffc64d7c Nikos Skalkotos
    """Upload the image to the storage service"""
117 023e1217 Nikos Skalkotos
    d = session["dialog"]
118 f5174d2c Nikos Skalkotos
    image = session['image']
119 66719e36 Nikos Skalkotos
    meta = session['metadata']
120 f5174d2c Nikos Skalkotos
    size = image.size
121 023e1217 Nikos Skalkotos
122 023e1217 Nikos Skalkotos
    if "account" not in session:
123 49c07ce3 Nikos Skalkotos
        d.msgbox("You need to select a valid cloud before you can upload "
124 ffc64d7c Nikos Skalkotos
                 "images to it", width=SMALL_WIDTH)
125 023e1217 Nikos Skalkotos
        return False
126 023e1217 Nikos Skalkotos
127 023e1217 Nikos Skalkotos
    while 1:
128 66719e36 Nikos Skalkotos
        if 'upload' in session:
129 66719e36 Nikos Skalkotos
            init = session['upload']
130 66719e36 Nikos Skalkotos
        elif 'OS' in meta:
131 66719e36 Nikos Skalkotos
            init = "%s.diskdump" % meta['OS']
132 66719e36 Nikos Skalkotos
        else:
133 66719e36 Nikos Skalkotos
            init = ""
134 023e1217 Nikos Skalkotos
        (code, answer) = d.inputbox("Please provide a filename:", init=init,
135 023e1217 Nikos Skalkotos
                                    width=WIDTH)
136 023e1217 Nikos Skalkotos
137 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
138 023e1217 Nikos Skalkotos
            return False
139 023e1217 Nikos Skalkotos
140 023e1217 Nikos Skalkotos
        filename = answer.strip()
141 023e1217 Nikos Skalkotos
        if len(filename) == 0:
142 023e1217 Nikos Skalkotos
            d.msgbox("Filename cannot be empty", width=SMALL_WIDTH)
143 023e1217 Nikos Skalkotos
            continue
144 03eb7dc8 Nikos Skalkotos
145 03eb7dc8 Nikos Skalkotos
        kamaki = Kamaki(session['account'], None)
146 03eb7dc8 Nikos Skalkotos
        overwrite = []
147 03eb7dc8 Nikos Skalkotos
        for f in (filename, "%s.md5sum" % filename, "%s.meta" % filename):
148 03eb7dc8 Nikos Skalkotos
            if kamaki.object_exists(f):
149 03eb7dc8 Nikos Skalkotos
                overwrite.append(f)
150 03eb7dc8 Nikos Skalkotos
151 03eb7dc8 Nikos Skalkotos
        if len(overwrite) > 0:
152 ffc64d7c Nikos Skalkotos
            if d.yesno("The following storage service object(s) already "
153 ffc64d7c Nikos Skalkotos
                       "exist(s):\n%s\nDo you want to overwrite them?" %
154 03eb7dc8 Nikos Skalkotos
                       "\n".join(overwrite), width=WIDTH, defaultno=1):
155 03eb7dc8 Nikos Skalkotos
                continue
156 03eb7dc8 Nikos Skalkotos
157 023e1217 Nikos Skalkotos
        session['upload'] = filename
158 023e1217 Nikos Skalkotos
        break
159 023e1217 Nikos Skalkotos
160 34e7a04a Nikos Skalkotos
    gauge = GaugeOutput(d, "Image Upload", "Uploading ...")
161 023e1217 Nikos Skalkotos
    try:
162 f5174d2c Nikos Skalkotos
        out = image.out
163 023e1217 Nikos Skalkotos
        out.add(gauge)
164 03eb7dc8 Nikos Skalkotos
        kamaki.out = out
165 023e1217 Nikos Skalkotos
        try:
166 023e1217 Nikos Skalkotos
            if 'checksum' not in session:
167 023e1217 Nikos Skalkotos
                md5 = MD5(out)
168 f5174d2c Nikos Skalkotos
                session['checksum'] = md5.compute(image.device, size)
169 023e1217 Nikos Skalkotos
170 023e1217 Nikos Skalkotos
            try:
171 023e1217 Nikos Skalkotos
                # Upload image file
172 f5174d2c Nikos Skalkotos
                with open(image.device, 'rb') as f:
173 023e1217 Nikos Skalkotos
                    session["pithos_uri"] = \
174 023e1217 Nikos Skalkotos
                        kamaki.upload(f, size, filename,
175 023e1217 Nikos Skalkotos
                                      "Calculating block hashes",
176 023e1217 Nikos Skalkotos
                                      "Uploading missing blocks")
177 023e1217 Nikos Skalkotos
                # Upload md5sum file
178 34e7a04a Nikos Skalkotos
                out.output("Uploading md5sum file ...")
179 023e1217 Nikos Skalkotos
                md5str = "%s %s\n" % (session['checksum'], filename)
180 023e1217 Nikos Skalkotos
                kamaki.upload(StringIO.StringIO(md5str), size=len(md5str),
181 023e1217 Nikos Skalkotos
                              remote_path="%s.md5sum" % filename)
182 023e1217 Nikos Skalkotos
                out.success("done")
183 023e1217 Nikos Skalkotos
184 023e1217 Nikos Skalkotos
            except ClientError as e:
185 ffc64d7c Nikos Skalkotos
                d.msgbox(
186 ffc64d7c Nikos Skalkotos
                    "Error in storage service client: %s" % e.message,
187 ffc64d7c Nikos Skalkotos
                    title="Storage Service Client Error", width=SMALL_WIDTH)
188 023e1217 Nikos Skalkotos
                if 'pithos_uri' in session:
189 023e1217 Nikos Skalkotos
                    del session['pithos_uri']
190 023e1217 Nikos Skalkotos
                return False
191 023e1217 Nikos Skalkotos
        finally:
192 023e1217 Nikos Skalkotos
            out.remove(gauge)
193 023e1217 Nikos Skalkotos
    finally:
194 023e1217 Nikos Skalkotos
        gauge.cleanup()
195 023e1217 Nikos Skalkotos
196 ffc64d7c Nikos Skalkotos
    d.msgbox("Image file `%s' was successfully uploaded" % filename,
197 023e1217 Nikos Skalkotos
             width=SMALL_WIDTH)
198 023e1217 Nikos Skalkotos
199 023e1217 Nikos Skalkotos
    return True
200 023e1217 Nikos Skalkotos
201 023e1217 Nikos Skalkotos
202 023e1217 Nikos Skalkotos
def register_image(session):
203 ffc64d7c Nikos Skalkotos
    """Register image with the compute service"""
204 023e1217 Nikos Skalkotos
    d = session["dialog"]
205 023e1217 Nikos Skalkotos
206 37d581b8 Nikos Skalkotos
    is_public = False
207 37d581b8 Nikos Skalkotos
208 023e1217 Nikos Skalkotos
    if "account" not in session:
209 49c07ce3 Nikos Skalkotos
        d.msgbox("You need to select a valid cloud before you "
210 ffc64d7c Nikos Skalkotos
                 "can register an images with it", width=SMALL_WIDTH)
211 023e1217 Nikos Skalkotos
        return False
212 023e1217 Nikos Skalkotos
213 023e1217 Nikos Skalkotos
    if "pithos_uri" not in session:
214 ffc64d7c Nikos Skalkotos
        d.msgbox("You need to upload the image to the cloud before you can "
215 ffc64d7c Nikos Skalkotos
                 "register it", width=SMALL_WIDTH)
216 023e1217 Nikos Skalkotos
        return False
217 023e1217 Nikos Skalkotos
218 023e1217 Nikos Skalkotos
    while 1:
219 023e1217 Nikos Skalkotos
        (code, answer) = d.inputbox("Please provide a registration name:",
220 023e1217 Nikos Skalkotos
                                    width=WIDTH)
221 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
222 023e1217 Nikos Skalkotos
            return False
223 023e1217 Nikos Skalkotos
224 023e1217 Nikos Skalkotos
        name = answer.strip()
225 023e1217 Nikos Skalkotos
        if len(name) == 0:
226 023e1217 Nikos Skalkotos
            d.msgbox("Registration name cannot be empty", width=SMALL_WIDTH)
227 023e1217 Nikos Skalkotos
            continue
228 37d581b8 Nikos Skalkotos
229 66719e36 Nikos Skalkotos
        ret = d.yesno("Make the image public?\\nA public image is accessible "
230 37d581b8 Nikos Skalkotos
                      "by every user of the service.", defaultno=1,
231 37d581b8 Nikos Skalkotos
                      width=WIDTH)
232 37d581b8 Nikos Skalkotos
        if ret not in (0, 1):
233 37d581b8 Nikos Skalkotos
            continue
234 37d581b8 Nikos Skalkotos
235 37d581b8 Nikos Skalkotos
        is_public = True if ret == 0 else False
236 37d581b8 Nikos Skalkotos
237 023e1217 Nikos Skalkotos
        break
238 023e1217 Nikos Skalkotos
239 023e1217 Nikos Skalkotos
    metadata = {}
240 023e1217 Nikos Skalkotos
    metadata.update(session['metadata'])
241 023e1217 Nikos Skalkotos
    if 'task_metadata' in session:
242 023e1217 Nikos Skalkotos
        for key in session['task_metadata']:
243 023e1217 Nikos Skalkotos
            metadata[key] = 'yes'
244 023e1217 Nikos Skalkotos
245 37d581b8 Nikos Skalkotos
    img_type = "public" if is_public else "private"
246 34e7a04a Nikos Skalkotos
    gauge = GaugeOutput(d, "Image Registration", "Registering image ...")
247 023e1217 Nikos Skalkotos
    try:
248 f5174d2c Nikos Skalkotos
        out = session['image'].out
249 023e1217 Nikos Skalkotos
        out.add(gauge)
250 023e1217 Nikos Skalkotos
        try:
251 023e1217 Nikos Skalkotos
            try:
252 34e7a04a Nikos Skalkotos
                out.output("Registering %s image with the cloud ..." %
253 34e7a04a Nikos Skalkotos
                           img_type)
254 31160dc8 Nikos Skalkotos
                kamaki = Kamaki(session['account'], out)
255 8e58e699 Nikos Skalkotos
                result = kamaki.register(name, session['pithos_uri'], metadata,
256 8e58e699 Nikos Skalkotos
                                         is_public)
257 023e1217 Nikos Skalkotos
                out.success('done')
258 03eb7dc8 Nikos Skalkotos
                # Upload metadata file
259 34e7a04a Nikos Skalkotos
                out.output("Uploading metadata file ...")
260 8e58e699 Nikos Skalkotos
                metastring = unicode(json.dumps(result, ensure_ascii=False))
261 03eb7dc8 Nikos Skalkotos
                kamaki.upload(StringIO.StringIO(metastring),
262 03eb7dc8 Nikos Skalkotos
                              size=len(metastring),
263 03eb7dc8 Nikos Skalkotos
                              remote_path="%s.meta" % session['upload'])
264 03eb7dc8 Nikos Skalkotos
                out.success("done")
265 3afe6b44 Nikos Skalkotos
                if is_public:
266 34e7a04a Nikos Skalkotos
                    out.output("Sharing metadata and md5sum files ...")
267 3afe6b44 Nikos Skalkotos
                    kamaki.share("%s.meta" % session['upload'])
268 3afe6b44 Nikos Skalkotos
                    kamaki.share("%s.md5sum" % session['upload'])
269 3afe6b44 Nikos Skalkotos
                    out.success('done')
270 023e1217 Nikos Skalkotos
            except ClientError as e:
271 ffc64d7c Nikos Skalkotos
                d.msgbox("Error in storage service client: %s" % e.message)
272 023e1217 Nikos Skalkotos
                return False
273 023e1217 Nikos Skalkotos
        finally:
274 023e1217 Nikos Skalkotos
            out.remove(gauge)
275 023e1217 Nikos Skalkotos
    finally:
276 023e1217 Nikos Skalkotos
        gauge.cleanup()
277 023e1217 Nikos Skalkotos
278 ffc64d7c Nikos Skalkotos
    d.msgbox("%s image `%s' was successfully registered with the cloud as `%s'"
279 37d581b8 Nikos Skalkotos
             % (img_type.title(), session['upload'], name), width=SMALL_WIDTH)
280 023e1217 Nikos Skalkotos
    return True
281 023e1217 Nikos Skalkotos
282 023e1217 Nikos Skalkotos
283 49c07ce3 Nikos Skalkotos
def modify_clouds(session):
284 49c07ce3 Nikos Skalkotos
    """Modify existing cloud accounts"""
285 49c07ce3 Nikos Skalkotos
    d = session['dialog']
286 49c07ce3 Nikos Skalkotos
287 49c07ce3 Nikos Skalkotos
    while 1:
288 49c07ce3 Nikos Skalkotos
        clouds = Kamaki.get_clouds()
289 49c07ce3 Nikos Skalkotos
        if not len(clouds):
290 49c07ce3 Nikos Skalkotos
            if not add_cloud(session):
291 49c07ce3 Nikos Skalkotos
                break
292 49c07ce3 Nikos Skalkotos
            continue
293 49c07ce3 Nikos Skalkotos
294 49c07ce3 Nikos Skalkotos
        choices = []
295 49c07ce3 Nikos Skalkotos
        for (name, cloud) in clouds.items():
296 49c07ce3 Nikos Skalkotos
            descr = cloud['description'] if 'description' in cloud else ''
297 49c07ce3 Nikos Skalkotos
            choices.append((name, descr))
298 49c07ce3 Nikos Skalkotos
299 49c07ce3 Nikos Skalkotos
        (code, choice) = d.menu(
300 49c07ce3 Nikos Skalkotos
            "In this menu you can edit existing cloud accounts or add new "
301 49c07ce3 Nikos Skalkotos
            " ones. Press <Edit> to edit an existing account or <Add> to add "
302 49c07ce3 Nikos Skalkotos
            " a new one. Press <Back> or hit <ESC> when done.", height=18,
303 49c07ce3 Nikos Skalkotos
            width=WIDTH, choices=choices, menu_height=10, ok_label="Edit",
304 49c07ce3 Nikos Skalkotos
            extra_button=1, extra_label="Add", cancel="Back", help_button=1,
305 49c07ce3 Nikos Skalkotos
            title="Clouds")
306 49c07ce3 Nikos Skalkotos
307 49c07ce3 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
308 49c07ce3 Nikos Skalkotos
            return True
309 49c07ce3 Nikos Skalkotos
        elif code == d.DIALOG_OK:  # Edit button
310 49c07ce3 Nikos Skalkotos
            edit_cloud(session, choice)
311 49c07ce3 Nikos Skalkotos
        elif code == d.DIALOG_EXTRA:  # Add button
312 49c07ce3 Nikos Skalkotos
            add_cloud(session)
313 49c07ce3 Nikos Skalkotos
314 49c07ce3 Nikos Skalkotos
315 49c07ce3 Nikos Skalkotos
def delete_clouds(session):
316 49c07ce3 Nikos Skalkotos
    """Delete existing cloud accounts"""
317 49c07ce3 Nikos Skalkotos
    d = session['dialog']
318 49c07ce3 Nikos Skalkotos
319 49c07ce3 Nikos Skalkotos
    choices = []
320 49c07ce3 Nikos Skalkotos
    for (name, cloud) in Kamaki.get_clouds().items():
321 49c07ce3 Nikos Skalkotos
        descr = cloud['description'] if 'description' in cloud else ''
322 49c07ce3 Nikos Skalkotos
        choices.append((name, descr, 0))
323 49c07ce3 Nikos Skalkotos
324 49c07ce3 Nikos Skalkotos
    if len(choices) == 0:
325 49c07ce3 Nikos Skalkotos
        d.msgbox("No available clouds to delete!", width=SMALL_WIDTH)
326 49c07ce3 Nikos Skalkotos
        return True
327 49c07ce3 Nikos Skalkotos
328 49c07ce3 Nikos Skalkotos
    (code, to_delete) = d.checklist("Choose which cloud accounts to delete:",
329 49c07ce3 Nikos Skalkotos
                                    choices=choices, width=WIDTH)
330 49c07ce3 Nikos Skalkotos
331 49c07ce3 Nikos Skalkotos
    if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
332 49c07ce3 Nikos Skalkotos
        return False
333 49c07ce3 Nikos Skalkotos
334 49c07ce3 Nikos Skalkotos
    if not len(to_delete):
335 49c07ce3 Nikos Skalkotos
        d.msgbox("Nothing selected!", width=SMALL_WIDTH)
336 49c07ce3 Nikos Skalkotos
        return False
337 49c07ce3 Nikos Skalkotos
338 49c07ce3 Nikos Skalkotos
    if not d.yesno("Are you sure you want to remove the selected cloud "
339 49c07ce3 Nikos Skalkotos
                   "accounts?", width=WIDTH, defaultno=1):
340 49c07ce3 Nikos Skalkotos
        for i in to_delete:
341 49c07ce3 Nikos Skalkotos
            Kamaki.remove_cloud(i)
342 49c07ce3 Nikos Skalkotos
            if 'cloud' in session and session['cloud'] == i:
343 49c07ce3 Nikos Skalkotos
                del session['cloud']
344 49c07ce3 Nikos Skalkotos
                if 'account' in session:
345 49c07ce3 Nikos Skalkotos
                    del session['account']
346 49c07ce3 Nikos Skalkotos
    else:
347 49c07ce3 Nikos Skalkotos
        return False
348 49c07ce3 Nikos Skalkotos
349 49c07ce3 Nikos Skalkotos
    d.msgbox("%d cloud accounts were deleted." % len(to_delete),
350 49c07ce3 Nikos Skalkotos
             width=SMALL_WIDTH)
351 49c07ce3 Nikos Skalkotos
    return True
352 49c07ce3 Nikos Skalkotos
353 49c07ce3 Nikos Skalkotos
354 023e1217 Nikos Skalkotos
def kamaki_menu(session):
355 88f83027 Nikos Skalkotos
    """Show kamaki related actions"""
356 023e1217 Nikos Skalkotos
    d = session['dialog']
357 49c07ce3 Nikos Skalkotos
    default_item = "Cloud"
358 023e1217 Nikos Skalkotos
359 49c07ce3 Nikos Skalkotos
    if 'cloud' not in session:
360 49c07ce3 Nikos Skalkotos
        cloud = Kamaki.get_default_cloud_name()
361 49c07ce3 Nikos Skalkotos
        if cloud:
362 49c07ce3 Nikos Skalkotos
            session['cloud'] = cloud
363 49c07ce3 Nikos Skalkotos
            session['account'] = Kamaki.get_account(cloud)
364 31160dc8 Nikos Skalkotos
            if not session['account']:
365 31160dc8 Nikos Skalkotos
                del session['account']
366 49c07ce3 Nikos Skalkotos
        else:
367 49c07ce3 Nikos Skalkotos
            default_item = "Add/Edit"
368 023e1217 Nikos Skalkotos
369 023e1217 Nikos Skalkotos
    while 1:
370 49c07ce3 Nikos Skalkotos
        cloud = session["cloud"] if "cloud" in session else "<none>"
371 49c07ce3 Nikos Skalkotos
        if 'account' not in session and 'cloud' in session:
372 49c07ce3 Nikos Skalkotos
            cloud += " <invalid>"
373 49c07ce3 Nikos Skalkotos
374 023e1217 Nikos Skalkotos
        upload = session["upload"] if "upload" in session else "<none>"
375 023e1217 Nikos Skalkotos
376 49c07ce3 Nikos Skalkotos
        choices = [("Add/Edit", "Add/Edit cloud accounts"),
377 49c07ce3 Nikos Skalkotos
                   ("Delete", "Delete existing cloud accounts"),
378 49c07ce3 Nikos Skalkotos
                   ("Cloud", "Select cloud account to use: %s" % cloud),
379 ffc64d7c Nikos Skalkotos
                   ("Upload", "Upload image to the cloud"),
380 ffc64d7c Nikos Skalkotos
                   ("Register", "Register image with the cloud: %s" % upload)]
381 023e1217 Nikos Skalkotos
382 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
383 023e1217 Nikos Skalkotos
            text="Choose one of the following or press <Back> to go back.",
384 023e1217 Nikos Skalkotos
            width=WIDTH, choices=choices, cancel="Back", height=13,
385 023e1217 Nikos Skalkotos
            menu_height=5, default_item=default_item,
386 023e1217 Nikos Skalkotos
            title="Image Registration Menu")
387 023e1217 Nikos Skalkotos
388 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
389 023e1217 Nikos Skalkotos
            return False
390 023e1217 Nikos Skalkotos
391 49c07ce3 Nikos Skalkotos
        if choice == "Add/Edit":
392 49c07ce3 Nikos Skalkotos
            if modify_clouds(session):
393 49c07ce3 Nikos Skalkotos
                default_item = "Cloud"
394 49c07ce3 Nikos Skalkotos
        elif choice == "Delete":
395 49c07ce3 Nikos Skalkotos
            if delete_clouds(session):
396 49c07ce3 Nikos Skalkotos
                if len(Kamaki.get_clouds()):
397 49c07ce3 Nikos Skalkotos
                    default_item = "Cloud"
398 49c07ce3 Nikos Skalkotos
                else:
399 49c07ce3 Nikos Skalkotos
                    default_time = "Add/Edit"
400 49c07ce3 Nikos Skalkotos
            else:
401 49c07ce3 Nikos Skalkotos
                default_time = "Delete"
402 49c07ce3 Nikos Skalkotos
        elif choice == "Cloud":
403 49c07ce3 Nikos Skalkotos
            default_item = "Cloud"
404 49c07ce3 Nikos Skalkotos
            clouds = Kamaki.get_clouds()
405 49c07ce3 Nikos Skalkotos
            if not len(clouds):
406 49c07ce3 Nikos Skalkotos
                d.msgbox("No clouds available. Please add a new cloud!",
407 49c07ce3 Nikos Skalkotos
                         width=SMALL_WIDTH)
408 49c07ce3 Nikos Skalkotos
                default_item = "Add/Edit"
409 49c07ce3 Nikos Skalkotos
                continue
410 49c07ce3 Nikos Skalkotos
411 49c07ce3 Nikos Skalkotos
            if 'cloud' not in session:
412 49c07ce3 Nikos Skalkotos
                session['cloud'] = clouds.keys()[0]
413 49c07ce3 Nikos Skalkotos
414 49c07ce3 Nikos Skalkotos
            choices = []
415 49c07ce3 Nikos Skalkotos
            for name, info in clouds.items():
416 49c07ce3 Nikos Skalkotos
                default = 1 if session['cloud'] == name else 0
417 49c07ce3 Nikos Skalkotos
                descr = info['description'] if 'description' in info else ""
418 49c07ce3 Nikos Skalkotos
                choices.append((name, descr, default))
419 49c07ce3 Nikos Skalkotos
420 49c07ce3 Nikos Skalkotos
            (code, answer) = d.radiolist("Please select a cloud:",
421 49c07ce3 Nikos Skalkotos
                                         width=WIDTH, choices=choices)
422 023e1217 Nikos Skalkotos
            if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
423 023e1217 Nikos Skalkotos
                continue
424 023e1217 Nikos Skalkotos
            else:
425 49c07ce3 Nikos Skalkotos
                session['account'] = Kamaki.get_account(answer)
426 49c07ce3 Nikos Skalkotos
427 49c07ce3 Nikos Skalkotos
                if session['account'] is None:  # invalid account
428 49c07ce3 Nikos Skalkotos
                    if not d.yesno("The cloud %s' is not valid! Would you "
429 49c07ce3 Nikos Skalkotos
                                   "like to edit it?" % answer, width=WIDTH):
430 49c07ce3 Nikos Skalkotos
                        if edit_cloud(session, answer):
431 49c07ce3 Nikos Skalkotos
                            session['account'] = Kamaki.get_account(answer)
432 49c07ce3 Nikos Skalkotos
                            Kamaki.set_default_cloud(answer)
433 49c07ce3 Nikos Skalkotos
434 31160dc8 Nikos Skalkotos
                if session['account'] is not None:
435 49c07ce3 Nikos Skalkotos
                    session['cloud'] = answer
436 49c07ce3 Nikos Skalkotos
                    Kamaki.set_default_cloud(answer)
437 31160dc8 Nikos Skalkotos
                    default_item = "Upload"
438 31160dc8 Nikos Skalkotos
                else:
439 31160dc8 Nikos Skalkotos
                    del session['account']
440 49c07ce3 Nikos Skalkotos
                    del session['cloud']
441 023e1217 Nikos Skalkotos
        elif choice == "Upload":
442 023e1217 Nikos Skalkotos
            if upload_image(session):
443 023e1217 Nikos Skalkotos
                default_item = "Register"
444 023e1217 Nikos Skalkotos
            else:
445 023e1217 Nikos Skalkotos
                default_item = "Upload"
446 023e1217 Nikos Skalkotos
        elif choice == "Register":
447 023e1217 Nikos Skalkotos
            if register_image(session):
448 023e1217 Nikos Skalkotos
                return True
449 023e1217 Nikos Skalkotos
            else:
450 023e1217 Nikos Skalkotos
                default_item = "Register"
451 023e1217 Nikos Skalkotos
452 023e1217 Nikos Skalkotos
453 023e1217 Nikos Skalkotos
def add_property(session):
454 88f83027 Nikos Skalkotos
    """Add a new property to the image"""
455 023e1217 Nikos Skalkotos
    d = session['dialog']
456 023e1217 Nikos Skalkotos
457 023e1217 Nikos Skalkotos
    while 1:
458 023e1217 Nikos Skalkotos
        (code, answer) = d.inputbox("Please provide a name for a new image"
459 023e1217 Nikos Skalkotos
                                    " property:", width=WIDTH)
460 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
461 023e1217 Nikos Skalkotos
            return False
462 023e1217 Nikos Skalkotos
463 023e1217 Nikos Skalkotos
        name = answer.strip()
464 023e1217 Nikos Skalkotos
        if len(name) == 0:
465 023e1217 Nikos Skalkotos
            d.msgbox("A property name cannot be empty", width=SMALL_WIDTH)
466 023e1217 Nikos Skalkotos
            continue
467 023e1217 Nikos Skalkotos
468 023e1217 Nikos Skalkotos
        break
469 023e1217 Nikos Skalkotos
470 023e1217 Nikos Skalkotos
    while 1:
471 023e1217 Nikos Skalkotos
        (code, answer) = d.inputbox("Please provide a value for image "
472 023e1217 Nikos Skalkotos
                                    "property %s" % name, width=WIDTH)
473 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
474 023e1217 Nikos Skalkotos
            return False
475 023e1217 Nikos Skalkotos
476 023e1217 Nikos Skalkotos
        value = answer.strip()
477 023e1217 Nikos Skalkotos
        if len(value) == 0:
478 023e1217 Nikos Skalkotos
            d.msgbox("Value cannot be empty", width=SMALL_WIDTH)
479 023e1217 Nikos Skalkotos
            continue
480 023e1217 Nikos Skalkotos
481 023e1217 Nikos Skalkotos
        break
482 023e1217 Nikos Skalkotos
483 023e1217 Nikos Skalkotos
    session['metadata'][name] = value
484 023e1217 Nikos Skalkotos
485 023e1217 Nikos Skalkotos
    return True
486 023e1217 Nikos Skalkotos
487 023e1217 Nikos Skalkotos
488 023e1217 Nikos Skalkotos
def modify_properties(session):
489 88f83027 Nikos Skalkotos
    """Modify an existing image property"""
490 023e1217 Nikos Skalkotos
    d = session['dialog']
491 023e1217 Nikos Skalkotos
492 023e1217 Nikos Skalkotos
    while 1:
493 023e1217 Nikos Skalkotos
        choices = []
494 023e1217 Nikos Skalkotos
        for (key, val) in session['metadata'].items():
495 023e1217 Nikos Skalkotos
            choices.append((str(key), str(val)))
496 023e1217 Nikos Skalkotos
497 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
498 023e1217 Nikos Skalkotos
            "In this menu you can edit existing image properties or add new "
499 023e1217 Nikos Skalkotos
            "ones. Be careful! Most properties have special meaning and "
500 023e1217 Nikos Skalkotos
            "alter the image deployment behaviour. Press <HELP> to see more "
501 023e1217 Nikos Skalkotos
            "information about image properties. Press <BACK> when done.",
502 023e1217 Nikos Skalkotos
            height=18, width=WIDTH, choices=choices, menu_height=10,
503 023e1217 Nikos Skalkotos
            ok_label="Edit", extra_button=1, extra_label="Add", cancel="Back",
504 023e1217 Nikos Skalkotos
            help_button=1, title="Image Properties")
505 023e1217 Nikos Skalkotos
506 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
507 023e1217 Nikos Skalkotos
            return True
508 023e1217 Nikos Skalkotos
        # Edit button
509 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_OK:
510 023e1217 Nikos Skalkotos
            (code, answer) = d.inputbox("Please provide a new value for the "
511 023e1217 Nikos Skalkotos
                                        "image property with name `%s':" %
512 023e1217 Nikos Skalkotos
                                        choice,
513 023e1217 Nikos Skalkotos
                                        init=session['metadata'][choice],
514 023e1217 Nikos Skalkotos
                                        width=WIDTH)
515 023e1217 Nikos Skalkotos
            if code not in (d.DIALOG_CANCEL, d.DIALOG_ESC):
516 023e1217 Nikos Skalkotos
                value = answer.strip()
517 023e1217 Nikos Skalkotos
                if len(value) == 0:
518 023e1217 Nikos Skalkotos
                    d.msgbox("Value cannot be empty!")
519 023e1217 Nikos Skalkotos
                    continue
520 023e1217 Nikos Skalkotos
                else:
521 023e1217 Nikos Skalkotos
                    session['metadata'][choice] = value
522 023e1217 Nikos Skalkotos
        # ADD button
523 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_EXTRA:
524 023e1217 Nikos Skalkotos
            add_property(session)
525 023e1217 Nikos Skalkotos
        elif code == 'help':
526 023e1217 Nikos Skalkotos
            help_file = get_help_file("image_properties")
527 023e1217 Nikos Skalkotos
            assert os.path.exists(help_file)
528 023e1217 Nikos Skalkotos
            d.textbox(help_file, title="Image Properties", width=70, height=40)
529 023e1217 Nikos Skalkotos
530 023e1217 Nikos Skalkotos
531 023e1217 Nikos Skalkotos
def delete_properties(session):
532 88f83027 Nikos Skalkotos
    """Delete an image property"""
533 023e1217 Nikos Skalkotos
    d = session['dialog']
534 023e1217 Nikos Skalkotos
535 023e1217 Nikos Skalkotos
    choices = []
536 023e1217 Nikos Skalkotos
    for (key, val) in session['metadata'].items():
537 023e1217 Nikos Skalkotos
        choices.append((key, "%s" % val, 0))
538 023e1217 Nikos Skalkotos
539 023e1217 Nikos Skalkotos
    (code, to_delete) = d.checklist("Choose which properties to delete:",
540 023e1217 Nikos Skalkotos
                                    choices=choices, width=WIDTH)
541 023e1217 Nikos Skalkotos
542 023e1217 Nikos Skalkotos
    # If the user exits with ESC or CANCEL, the returned tag list is empty.
543 023e1217 Nikos Skalkotos
    for i in to_delete:
544 023e1217 Nikos Skalkotos
        del session['metadata'][i]
545 023e1217 Nikos Skalkotos
546 023e1217 Nikos Skalkotos
    cnt = len(to_delete)
547 023e1217 Nikos Skalkotos
    if cnt > 0:
548 023e1217 Nikos Skalkotos
        d.msgbox("%d image properties were deleted." % cnt, width=SMALL_WIDTH)
549 023e1217 Nikos Skalkotos
        return True
550 023e1217 Nikos Skalkotos
    else:
551 023e1217 Nikos Skalkotos
        return False
552 023e1217 Nikos Skalkotos
553 023e1217 Nikos Skalkotos
554 023e1217 Nikos Skalkotos
def exclude_tasks(session):
555 88f83027 Nikos Skalkotos
    """Exclude specific tasks from running during image deployment"""
556 023e1217 Nikos Skalkotos
    d = session['dialog']
557 023e1217 Nikos Skalkotos
558 023e1217 Nikos Skalkotos
    index = 0
559 023e1217 Nikos Skalkotos
    displayed_index = 1
560 023e1217 Nikos Skalkotos
    choices = []
561 023e1217 Nikos Skalkotos
    mapping = {}
562 023e1217 Nikos Skalkotos
    if 'excluded_tasks' not in session:
563 023e1217 Nikos Skalkotos
        session['excluded_tasks'] = []
564 023e1217 Nikos Skalkotos
565 023e1217 Nikos Skalkotos
    if -1 in session['excluded_tasks']:
566 023e1217 Nikos Skalkotos
        if not d.yesno("Image deployment configuration is disabled. "
567 023e1217 Nikos Skalkotos
                       "Do you wish to enable it?", width=SMALL_WIDTH):
568 023e1217 Nikos Skalkotos
            session['excluded_tasks'].remove(-1)
569 023e1217 Nikos Skalkotos
        else:
570 023e1217 Nikos Skalkotos
            return False
571 023e1217 Nikos Skalkotos
572 023e1217 Nikos Skalkotos
    for (msg, task, osfamily) in CONFIGURATION_TASKS:
573 023e1217 Nikos Skalkotos
        if session['metadata']['OSFAMILY'] in osfamily:
574 023e1217 Nikos Skalkotos
            checked = 1 if index in session['excluded_tasks'] else 0
575 023e1217 Nikos Skalkotos
            choices.append((str(displayed_index), msg, checked))
576 023e1217 Nikos Skalkotos
            mapping[displayed_index] = index
577 023e1217 Nikos Skalkotos
            displayed_index += 1
578 023e1217 Nikos Skalkotos
        index += 1
579 023e1217 Nikos Skalkotos
580 023e1217 Nikos Skalkotos
    while 1:
581 023e1217 Nikos Skalkotos
        (code, tags) = d.checklist(
582 023e1217 Nikos Skalkotos
            text="Please choose which configuration tasks you would like to "
583 023e1217 Nikos Skalkotos
                 "prevent from running during image deployment. "
584 023e1217 Nikos Skalkotos
                 "Press <No Config> to supress any configuration. "
585 023e1217 Nikos Skalkotos
                 "Press <Help> for more help on the image deployment "
586 023e1217 Nikos Skalkotos
                 "configuration tasks.",
587 023e1217 Nikos Skalkotos
            choices=choices, height=19, list_height=8, width=WIDTH,
588 023e1217 Nikos Skalkotos
            help_button=1, extra_button=1, extra_label="No Config",
589 023e1217 Nikos Skalkotos
            title="Exclude Configuration Tasks")
590 023e1217 Nikos Skalkotos
591 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
592 023e1217 Nikos Skalkotos
            return False
593 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_HELP:
594 023e1217 Nikos Skalkotos
            help_file = get_help_file("configuration_tasks")
595 023e1217 Nikos Skalkotos
            assert os.path.exists(help_file)
596 023e1217 Nikos Skalkotos
            d.textbox(help_file, title="Configuration Tasks",
597 023e1217 Nikos Skalkotos
                      width=70, height=40)
598 023e1217 Nikos Skalkotos
        # No Config button
599 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_EXTRA:
600 023e1217 Nikos Skalkotos
            session['excluded_tasks'] = [-1]
601 023e1217 Nikos Skalkotos
            session['task_metadata'] = ["EXCLUDE_ALL_TASKS"]
602 023e1217 Nikos Skalkotos
            break
603 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_OK:
604 023e1217 Nikos Skalkotos
            session['excluded_tasks'] = []
605 023e1217 Nikos Skalkotos
            for tag in tags:
606 023e1217 Nikos Skalkotos
                session['excluded_tasks'].append(mapping[int(tag)])
607 023e1217 Nikos Skalkotos
608 023e1217 Nikos Skalkotos
            exclude_metadata = []
609 023e1217 Nikos Skalkotos
            for task in session['excluded_tasks']:
610 023e1217 Nikos Skalkotos
                exclude_metadata.extend(CONFIGURATION_TASKS[task][1])
611 023e1217 Nikos Skalkotos
612 023e1217 Nikos Skalkotos
            session['task_metadata'] = map(lambda x: "EXCLUDE_TASK_%s" % x,
613 023e1217 Nikos Skalkotos
                                           exclude_metadata)
614 023e1217 Nikos Skalkotos
            break
615 023e1217 Nikos Skalkotos
616 023e1217 Nikos Skalkotos
    return True
617 023e1217 Nikos Skalkotos
618 023e1217 Nikos Skalkotos
619 023e1217 Nikos Skalkotos
def sysprep(session):
620 88f83027 Nikos Skalkotos
    """Perform various system preperation tasks on the image"""
621 023e1217 Nikos Skalkotos
    d = session['dialog']
622 f5174d2c Nikos Skalkotos
    image = session['image']
623 023e1217 Nikos Skalkotos
624 023e1217 Nikos Skalkotos
    # Is the image already shrinked?
625 023e1217 Nikos Skalkotos
    if 'shrinked' in session and session['shrinked']:
626 023e1217 Nikos Skalkotos
        msg = "It seems you have shrinked the image. Running system " \
627 023e1217 Nikos Skalkotos
              "preparation tasks on a shrinked image is dangerous."
628 023e1217 Nikos Skalkotos
629 023e1217 Nikos Skalkotos
        if d.yesno("%s\n\nDo you really want to continue?" % msg,
630 023e1217 Nikos Skalkotos
                   width=SMALL_WIDTH, defaultno=1):
631 023e1217 Nikos Skalkotos
            return
632 023e1217 Nikos Skalkotos
633 023e1217 Nikos Skalkotos
    wrapper = textwrap.TextWrapper(width=WIDTH - 5)
634 023e1217 Nikos Skalkotos
635 023e1217 Nikos Skalkotos
    help_title = "System Preperation Tasks"
636 023e1217 Nikos Skalkotos
    sysprep_help = "%s\n%s\n\n" % (help_title, '=' * len(help_title))
637 023e1217 Nikos Skalkotos
638 fa65eda1 Nikos Skalkotos
    syspreps = image.os.list_syspreps()
639 023e1217 Nikos Skalkotos
640 023e1217 Nikos Skalkotos
    if len(syspreps) == 0:
641 023e1217 Nikos Skalkotos
        d.msgbox("No system preparation task available to run!",
642 023e1217 Nikos Skalkotos
                 title="System Preperation", width=SMALL_WIDTH)
643 023e1217 Nikos Skalkotos
        return
644 023e1217 Nikos Skalkotos
645 023e1217 Nikos Skalkotos
    while 1:
646 023e1217 Nikos Skalkotos
        choices = []
647 023e1217 Nikos Skalkotos
        index = 0
648 023e1217 Nikos Skalkotos
        for sysprep in syspreps:
649 f5174d2c Nikos Skalkotos
            name, descr = image.os.sysprep_info(sysprep)
650 023e1217 Nikos Skalkotos
            display_name = name.replace('-', ' ').capitalize()
651 023e1217 Nikos Skalkotos
            sysprep_help += "%s\n" % display_name
652 023e1217 Nikos Skalkotos
            sysprep_help += "%s\n" % ('-' * len(display_name))
653 023e1217 Nikos Skalkotos
            sysprep_help += "%s\n\n" % wrapper.fill(" ".join(descr.split()))
654 023e1217 Nikos Skalkotos
            enabled = 1 if sysprep.enabled else 0
655 023e1217 Nikos Skalkotos
            choices.append((str(index + 1), display_name, enabled))
656 023e1217 Nikos Skalkotos
            index += 1
657 023e1217 Nikos Skalkotos
658 023e1217 Nikos Skalkotos
        (code, tags) = d.checklist(
659 023e1217 Nikos Skalkotos
            "Please choose which system preparation tasks you would like to "
660 023e1217 Nikos Skalkotos
            "run on the image. Press <Help> to see details about the system "
661 023e1217 Nikos Skalkotos
            "preparation tasks.", title="Run system preparation tasks",
662 023e1217 Nikos Skalkotos
            choices=choices, width=70, ok_label="Run", help_button=1)
663 023e1217 Nikos Skalkotos
664 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
665 023e1217 Nikos Skalkotos
            return False
666 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_HELP:
667 023e1217 Nikos Skalkotos
            d.scrollbox(sysprep_help, width=WIDTH)
668 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_OK:
669 023e1217 Nikos Skalkotos
            # Enable selected syspreps and disable the rest
670 023e1217 Nikos Skalkotos
            for i in range(len(syspreps)):
671 023e1217 Nikos Skalkotos
                if str(i + 1) in tags:
672 f5174d2c Nikos Skalkotos
                    image.os.enable_sysprep(syspreps[i])
673 023e1217 Nikos Skalkotos
                else:
674 f5174d2c Nikos Skalkotos
                    image.os.disable_sysprep(syspreps[i])
675 023e1217 Nikos Skalkotos
676 fa65eda1 Nikos Skalkotos
            if len([s for s in image.os.list_syspreps() if s.enabled]) == 0:
677 fa65eda1 Nikos Skalkotos
                d.msgbox("No system preperation task is selected!",
678 fa65eda1 Nikos Skalkotos
                         title="System Preperation", width=SMALL_WIDTH)
679 fa65eda1 Nikos Skalkotos
                continue
680 fa65eda1 Nikos Skalkotos
681 023e1217 Nikos Skalkotos
            infobox = InfoBoxOutput(d, "Image Configuration")
682 023e1217 Nikos Skalkotos
            try:
683 f5174d2c Nikos Skalkotos
                image.out.add(infobox)
684 023e1217 Nikos Skalkotos
                try:
685 71b0ab28 Nikos Skalkotos
                    # The checksum is invalid. We have mounted the image rw
686 71b0ab28 Nikos Skalkotos
                    if 'checksum' in session:
687 71b0ab28 Nikos Skalkotos
                        del session['checksum']
688 71b0ab28 Nikos Skalkotos
689 71b0ab28 Nikos Skalkotos
                    # Monitor the metadata changes during syspreps
690 71b0ab28 Nikos Skalkotos
                    with MetadataMonitor(session, image.os.meta):
691 71b0ab28 Nikos Skalkotos
                        try:
692 f5174d2c Nikos Skalkotos
                            image.os.do_sysprep()
693 023e1217 Nikos Skalkotos
                            infobox.finalize()
694 71b0ab28 Nikos Skalkotos
                        except FatalError as e:
695 71b0ab28 Nikos Skalkotos
                            title = "System Preparation"
696 71b0ab28 Nikos Skalkotos
                            d.msgbox("System Preparation failed: %s" % e,
697 71b0ab28 Nikos Skalkotos
                                     title=title, width=SMALL_WIDTH)
698 023e1217 Nikos Skalkotos
                finally:
699 f5174d2c Nikos Skalkotos
                    image.out.remove(infobox)
700 023e1217 Nikos Skalkotos
            finally:
701 023e1217 Nikos Skalkotos
                infobox.cleanup()
702 023e1217 Nikos Skalkotos
            break
703 023e1217 Nikos Skalkotos
    return True
704 023e1217 Nikos Skalkotos
705 023e1217 Nikos Skalkotos
706 023e1217 Nikos Skalkotos
def shrink(session):
707 88f83027 Nikos Skalkotos
    """Shrink the image"""
708 023e1217 Nikos Skalkotos
    d = session['dialog']
709 f5174d2c Nikos Skalkotos
    image = session['image']
710 023e1217 Nikos Skalkotos
711 023e1217 Nikos Skalkotos
    shrinked = 'shrinked' in session and session['shrinked']
712 023e1217 Nikos Skalkotos
713 023e1217 Nikos Skalkotos
    if shrinked:
714 023e1217 Nikos Skalkotos
        d.msgbox("The image is already shrinked!", title="Image Shrinking",
715 023e1217 Nikos Skalkotos
                 width=SMALL_WIDTH)
716 023e1217 Nikos Skalkotos
        return True
717 023e1217 Nikos Skalkotos
718 023e1217 Nikos Skalkotos
    msg = "This operation will shrink the last partition of the image to " \
719 023e1217 Nikos Skalkotos
          "reduce the total image size. If the last partition is a swap " \
720 023e1217 Nikos Skalkotos
          "partition, then this partition is removed and the partition " \
721 023e1217 Nikos Skalkotos
          "before that is shrinked. The removed swap partition will be " \
722 023e1217 Nikos Skalkotos
          "recreated during image deployment."
723 023e1217 Nikos Skalkotos
724 023e1217 Nikos Skalkotos
    if not d.yesno("%s\n\nDo you want to continue?" % msg, width=WIDTH,
725 023e1217 Nikos Skalkotos
                   height=12, title="Image Shrinking"):
726 f5174d2c Nikos Skalkotos
        with MetadataMonitor(session, image.meta):
727 023e1217 Nikos Skalkotos
            infobox = InfoBoxOutput(d, "Image Shrinking", height=4)
728 f5174d2c Nikos Skalkotos
            image.out.add(infobox)
729 023e1217 Nikos Skalkotos
            try:
730 f5174d2c Nikos Skalkotos
                image.shrink()
731 023e1217 Nikos Skalkotos
                infobox.finalize()
732 023e1217 Nikos Skalkotos
            finally:
733 f5174d2c Nikos Skalkotos
                image.out.remove(infobox)
734 023e1217 Nikos Skalkotos
735 023e1217 Nikos Skalkotos
        session['shrinked'] = True
736 023e1217 Nikos Skalkotos
        update_background_title(session)
737 023e1217 Nikos Skalkotos
    else:
738 023e1217 Nikos Skalkotos
        return False
739 023e1217 Nikos Skalkotos
740 023e1217 Nikos Skalkotos
    return True
741 023e1217 Nikos Skalkotos
742 023e1217 Nikos Skalkotos
743 023e1217 Nikos Skalkotos
def customization_menu(session):
744 88f83027 Nikos Skalkotos
    """Show image customization menu"""
745 023e1217 Nikos Skalkotos
    d = session['dialog']
746 023e1217 Nikos Skalkotos
747 023e1217 Nikos Skalkotos
    choices = [("Sysprep", "Run various image preparation tasks"),
748 023e1217 Nikos Skalkotos
               ("Shrink", "Shrink image"),
749 023e1217 Nikos Skalkotos
               ("View/Modify", "View/Modify image properties"),
750 023e1217 Nikos Skalkotos
               ("Delete", "Delete image properties"),
751 023e1217 Nikos Skalkotos
               ("Exclude", "Exclude various deployment tasks from running")]
752 023e1217 Nikos Skalkotos
753 023e1217 Nikos Skalkotos
    default_item = 0
754 023e1217 Nikos Skalkotos
755 023e1217 Nikos Skalkotos
    actions = {"Sysprep": sysprep,
756 023e1217 Nikos Skalkotos
               "Shrink": shrink,
757 023e1217 Nikos Skalkotos
               "View/Modify": modify_properties,
758 023e1217 Nikos Skalkotos
               "Delete": delete_properties,
759 023e1217 Nikos Skalkotos
               "Exclude": exclude_tasks}
760 023e1217 Nikos Skalkotos
    while 1:
761 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
762 023e1217 Nikos Skalkotos
            text="Choose one of the following or press <Back> to exit.",
763 023e1217 Nikos Skalkotos
            width=WIDTH, choices=choices, cancel="Back", height=13,
764 023e1217 Nikos Skalkotos
            menu_height=len(choices), default_item=choices[default_item][0],
765 023e1217 Nikos Skalkotos
            title="Image Customization Menu")
766 023e1217 Nikos Skalkotos
767 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
768 023e1217 Nikos Skalkotos
            break
769 023e1217 Nikos Skalkotos
        elif choice in actions:
770 023e1217 Nikos Skalkotos
            default_item = [entry[0] for entry in choices].index(choice)
771 023e1217 Nikos Skalkotos
            if actions[choice](session):
772 023e1217 Nikos Skalkotos
                default_item = (default_item + 1) % len(choices)
773 023e1217 Nikos Skalkotos
774 023e1217 Nikos Skalkotos
775 023e1217 Nikos Skalkotos
def main_menu(session):
776 88f83027 Nikos Skalkotos
    """Show the main menu of the program"""
777 023e1217 Nikos Skalkotos
    d = session['dialog']
778 023e1217 Nikos Skalkotos
779 023e1217 Nikos Skalkotos
    update_background_title(session)
780 023e1217 Nikos Skalkotos
781 49c07ce3 Nikos Skalkotos
    choices = [("Customize", "Customize image & cloud deployment options"),
782 49c07ce3 Nikos Skalkotos
               ("Register", "Register image to a cloud"),
783 023e1217 Nikos Skalkotos
               ("Extract", "Dump image to local file system"),
784 023e1217 Nikos Skalkotos
               ("Reset", "Reset everything and start over again"),
785 023e1217 Nikos Skalkotos
               ("Help", "Get help for using snf-image-creator")]
786 023e1217 Nikos Skalkotos
787 023e1217 Nikos Skalkotos
    default_item = "Customize"
788 023e1217 Nikos Skalkotos
789 023e1217 Nikos Skalkotos
    actions = {"Customize": customization_menu, "Register": kamaki_menu,
790 023e1217 Nikos Skalkotos
               "Extract": extract_image}
791 023e1217 Nikos Skalkotos
    while 1:
792 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
793 023e1217 Nikos Skalkotos
            text="Choose one of the following or press <Exit> to exit.",
794 023e1217 Nikos Skalkotos
            width=WIDTH, choices=choices, cancel="Exit", height=13,
795 023e1217 Nikos Skalkotos
            default_item=default_item, menu_height=len(choices),
796 ffc64d7c Nikos Skalkotos
            title="Image Creator for synnefo (snf-image-creator version %s)" %
797 023e1217 Nikos Skalkotos
                  version)
798 023e1217 Nikos Skalkotos
799 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
800 023e1217 Nikos Skalkotos
            if confirm_exit(d):
801 023e1217 Nikos Skalkotos
                break
802 023e1217 Nikos Skalkotos
        elif choice == "Reset":
803 023e1217 Nikos Skalkotos
            if confirm_reset(d):
804 34e7a04a Nikos Skalkotos
                d.infobox("Resetting snf-image-creator. Please wait ...",
805 023e1217 Nikos Skalkotos
                          width=SMALL_WIDTH)
806 023e1217 Nikos Skalkotos
                raise Reset
807 aa04fb4e Nikos Skalkotos
        elif choice == "Help":
808 aa04fb4e Nikos Skalkotos
            d.msgbox("For help, check the online documentation:\n\nhttp://www"
809 aa04fb4e Nikos Skalkotos
                     ".synnefo.org/docs/snf-image-creator/latest/",
810 aa04fb4e Nikos Skalkotos
                     width=WIDTH, title="Help")
811 023e1217 Nikos Skalkotos
        elif choice in actions:
812 023e1217 Nikos Skalkotos
            actions[choice](session)
813 023e1217 Nikos Skalkotos
814 023e1217 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :