Statistics
| Branch: | Tag: | Revision:

root / image_creator / dialog_menu.py @ 684a5524

History | View | Annotate | Download (30.5 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 5e18a927 Nikos Skalkotos
    to_delete = map(lambda x: x.strip('"'), to_delete)  # Needed for OpenSUSE
331 49c07ce3 Nikos Skalkotos
332 49c07ce3 Nikos Skalkotos
    if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
333 49c07ce3 Nikos Skalkotos
        return False
334 49c07ce3 Nikos Skalkotos
335 49c07ce3 Nikos Skalkotos
    if not len(to_delete):
336 49c07ce3 Nikos Skalkotos
        d.msgbox("Nothing selected!", width=SMALL_WIDTH)
337 49c07ce3 Nikos Skalkotos
        return False
338 49c07ce3 Nikos Skalkotos
339 49c07ce3 Nikos Skalkotos
    if not d.yesno("Are you sure you want to remove the selected cloud "
340 49c07ce3 Nikos Skalkotos
                   "accounts?", width=WIDTH, defaultno=1):
341 49c07ce3 Nikos Skalkotos
        for i in to_delete:
342 49c07ce3 Nikos Skalkotos
            Kamaki.remove_cloud(i)
343 49c07ce3 Nikos Skalkotos
            if 'cloud' in session and session['cloud'] == i:
344 49c07ce3 Nikos Skalkotos
                del session['cloud']
345 49c07ce3 Nikos Skalkotos
                if 'account' in session:
346 49c07ce3 Nikos Skalkotos
                    del session['account']
347 49c07ce3 Nikos Skalkotos
    else:
348 49c07ce3 Nikos Skalkotos
        return False
349 49c07ce3 Nikos Skalkotos
350 49c07ce3 Nikos Skalkotos
    d.msgbox("%d cloud accounts were deleted." % len(to_delete),
351 49c07ce3 Nikos Skalkotos
             width=SMALL_WIDTH)
352 49c07ce3 Nikos Skalkotos
    return True
353 49c07ce3 Nikos Skalkotos
354 49c07ce3 Nikos Skalkotos
355 023e1217 Nikos Skalkotos
def kamaki_menu(session):
356 88f83027 Nikos Skalkotos
    """Show kamaki related actions"""
357 023e1217 Nikos Skalkotos
    d = session['dialog']
358 49c07ce3 Nikos Skalkotos
    default_item = "Cloud"
359 023e1217 Nikos Skalkotos
360 49c07ce3 Nikos Skalkotos
    if 'cloud' not in session:
361 49c07ce3 Nikos Skalkotos
        cloud = Kamaki.get_default_cloud_name()
362 49c07ce3 Nikos Skalkotos
        if cloud:
363 49c07ce3 Nikos Skalkotos
            session['cloud'] = cloud
364 49c07ce3 Nikos Skalkotos
            session['account'] = Kamaki.get_account(cloud)
365 31160dc8 Nikos Skalkotos
            if not session['account']:
366 31160dc8 Nikos Skalkotos
                del session['account']
367 49c07ce3 Nikos Skalkotos
        else:
368 49c07ce3 Nikos Skalkotos
            default_item = "Add/Edit"
369 023e1217 Nikos Skalkotos
370 023e1217 Nikos Skalkotos
    while 1:
371 49c07ce3 Nikos Skalkotos
        cloud = session["cloud"] if "cloud" in session else "<none>"
372 49c07ce3 Nikos Skalkotos
        if 'account' not in session and 'cloud' in session:
373 49c07ce3 Nikos Skalkotos
            cloud += " <invalid>"
374 49c07ce3 Nikos Skalkotos
375 023e1217 Nikos Skalkotos
        upload = session["upload"] if "upload" in session else "<none>"
376 023e1217 Nikos Skalkotos
377 49c07ce3 Nikos Skalkotos
        choices = [("Add/Edit", "Add/Edit cloud accounts"),
378 49c07ce3 Nikos Skalkotos
                   ("Delete", "Delete existing cloud accounts"),
379 49c07ce3 Nikos Skalkotos
                   ("Cloud", "Select cloud account to use: %s" % cloud),
380 ffc64d7c Nikos Skalkotos
                   ("Upload", "Upload image to the cloud"),
381 ffc64d7c Nikos Skalkotos
                   ("Register", "Register image with the cloud: %s" % upload)]
382 023e1217 Nikos Skalkotos
383 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
384 023e1217 Nikos Skalkotos
            text="Choose one of the following or press <Back> to go back.",
385 023e1217 Nikos Skalkotos
            width=WIDTH, choices=choices, cancel="Back", height=13,
386 023e1217 Nikos Skalkotos
            menu_height=5, default_item=default_item,
387 023e1217 Nikos Skalkotos
            title="Image Registration Menu")
388 023e1217 Nikos Skalkotos
389 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
390 023e1217 Nikos Skalkotos
            return False
391 023e1217 Nikos Skalkotos
392 49c07ce3 Nikos Skalkotos
        if choice == "Add/Edit":
393 49c07ce3 Nikos Skalkotos
            if modify_clouds(session):
394 49c07ce3 Nikos Skalkotos
                default_item = "Cloud"
395 49c07ce3 Nikos Skalkotos
        elif choice == "Delete":
396 49c07ce3 Nikos Skalkotos
            if delete_clouds(session):
397 49c07ce3 Nikos Skalkotos
                if len(Kamaki.get_clouds()):
398 49c07ce3 Nikos Skalkotos
                    default_item = "Cloud"
399 49c07ce3 Nikos Skalkotos
                else:
400 49c07ce3 Nikos Skalkotos
                    default_time = "Add/Edit"
401 49c07ce3 Nikos Skalkotos
            else:
402 49c07ce3 Nikos Skalkotos
                default_time = "Delete"
403 49c07ce3 Nikos Skalkotos
        elif choice == "Cloud":
404 49c07ce3 Nikos Skalkotos
            default_item = "Cloud"
405 49c07ce3 Nikos Skalkotos
            clouds = Kamaki.get_clouds()
406 49c07ce3 Nikos Skalkotos
            if not len(clouds):
407 49c07ce3 Nikos Skalkotos
                d.msgbox("No clouds available. Please add a new cloud!",
408 49c07ce3 Nikos Skalkotos
                         width=SMALL_WIDTH)
409 49c07ce3 Nikos Skalkotos
                default_item = "Add/Edit"
410 49c07ce3 Nikos Skalkotos
                continue
411 49c07ce3 Nikos Skalkotos
412 49c07ce3 Nikos Skalkotos
            if 'cloud' not in session:
413 49c07ce3 Nikos Skalkotos
                session['cloud'] = clouds.keys()[0]
414 49c07ce3 Nikos Skalkotos
415 49c07ce3 Nikos Skalkotos
            choices = []
416 49c07ce3 Nikos Skalkotos
            for name, info in clouds.items():
417 49c07ce3 Nikos Skalkotos
                default = 1 if session['cloud'] == name else 0
418 49c07ce3 Nikos Skalkotos
                descr = info['description'] if 'description' in info else ""
419 49c07ce3 Nikos Skalkotos
                choices.append((name, descr, default))
420 49c07ce3 Nikos Skalkotos
421 49c07ce3 Nikos Skalkotos
            (code, answer) = d.radiolist("Please select a cloud:",
422 49c07ce3 Nikos Skalkotos
                                         width=WIDTH, choices=choices)
423 023e1217 Nikos Skalkotos
            if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
424 023e1217 Nikos Skalkotos
                continue
425 023e1217 Nikos Skalkotos
            else:
426 49c07ce3 Nikos Skalkotos
                session['account'] = Kamaki.get_account(answer)
427 49c07ce3 Nikos Skalkotos
428 49c07ce3 Nikos Skalkotos
                if session['account'] is None:  # invalid account
429 49c07ce3 Nikos Skalkotos
                    if not d.yesno("The cloud %s' is not valid! Would you "
430 49c07ce3 Nikos Skalkotos
                                   "like to edit it?" % answer, width=WIDTH):
431 49c07ce3 Nikos Skalkotos
                        if edit_cloud(session, answer):
432 49c07ce3 Nikos Skalkotos
                            session['account'] = Kamaki.get_account(answer)
433 49c07ce3 Nikos Skalkotos
                            Kamaki.set_default_cloud(answer)
434 49c07ce3 Nikos Skalkotos
435 31160dc8 Nikos Skalkotos
                if session['account'] is not None:
436 49c07ce3 Nikos Skalkotos
                    session['cloud'] = answer
437 49c07ce3 Nikos Skalkotos
                    Kamaki.set_default_cloud(answer)
438 31160dc8 Nikos Skalkotos
                    default_item = "Upload"
439 31160dc8 Nikos Skalkotos
                else:
440 31160dc8 Nikos Skalkotos
                    del session['account']
441 49c07ce3 Nikos Skalkotos
                    del session['cloud']
442 023e1217 Nikos Skalkotos
        elif choice == "Upload":
443 023e1217 Nikos Skalkotos
            if upload_image(session):
444 023e1217 Nikos Skalkotos
                default_item = "Register"
445 023e1217 Nikos Skalkotos
            else:
446 023e1217 Nikos Skalkotos
                default_item = "Upload"
447 023e1217 Nikos Skalkotos
        elif choice == "Register":
448 023e1217 Nikos Skalkotos
            if register_image(session):
449 023e1217 Nikos Skalkotos
                return True
450 023e1217 Nikos Skalkotos
            else:
451 023e1217 Nikos Skalkotos
                default_item = "Register"
452 023e1217 Nikos Skalkotos
453 023e1217 Nikos Skalkotos
454 023e1217 Nikos Skalkotos
def add_property(session):
455 88f83027 Nikos Skalkotos
    """Add a new property to the image"""
456 023e1217 Nikos Skalkotos
    d = session['dialog']
457 023e1217 Nikos Skalkotos
458 023e1217 Nikos Skalkotos
    while 1:
459 023e1217 Nikos Skalkotos
        (code, answer) = d.inputbox("Please provide a name for a new image"
460 023e1217 Nikos Skalkotos
                                    " property:", width=WIDTH)
461 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
462 023e1217 Nikos Skalkotos
            return False
463 023e1217 Nikos Skalkotos
464 023e1217 Nikos Skalkotos
        name = answer.strip()
465 023e1217 Nikos Skalkotos
        if len(name) == 0:
466 023e1217 Nikos Skalkotos
            d.msgbox("A property name cannot be empty", width=SMALL_WIDTH)
467 023e1217 Nikos Skalkotos
            continue
468 023e1217 Nikos Skalkotos
469 023e1217 Nikos Skalkotos
        break
470 023e1217 Nikos Skalkotos
471 023e1217 Nikos Skalkotos
    while 1:
472 023e1217 Nikos Skalkotos
        (code, answer) = d.inputbox("Please provide a value for image "
473 023e1217 Nikos Skalkotos
                                    "property %s" % name, width=WIDTH)
474 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
475 023e1217 Nikos Skalkotos
            return False
476 023e1217 Nikos Skalkotos
477 023e1217 Nikos Skalkotos
        value = answer.strip()
478 023e1217 Nikos Skalkotos
        if len(value) == 0:
479 023e1217 Nikos Skalkotos
            d.msgbox("Value cannot be empty", width=SMALL_WIDTH)
480 023e1217 Nikos Skalkotos
            continue
481 023e1217 Nikos Skalkotos
482 023e1217 Nikos Skalkotos
        break
483 023e1217 Nikos Skalkotos
484 023e1217 Nikos Skalkotos
    session['metadata'][name] = value
485 023e1217 Nikos Skalkotos
486 023e1217 Nikos Skalkotos
    return True
487 023e1217 Nikos Skalkotos
488 023e1217 Nikos Skalkotos
489 023e1217 Nikos Skalkotos
def modify_properties(session):
490 88f83027 Nikos Skalkotos
    """Modify an existing image property"""
491 023e1217 Nikos Skalkotos
    d = session['dialog']
492 023e1217 Nikos Skalkotos
493 023e1217 Nikos Skalkotos
    while 1:
494 023e1217 Nikos Skalkotos
        choices = []
495 023e1217 Nikos Skalkotos
        for (key, val) in session['metadata'].items():
496 023e1217 Nikos Skalkotos
            choices.append((str(key), str(val)))
497 023e1217 Nikos Skalkotos
498 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
499 023e1217 Nikos Skalkotos
            "In this menu you can edit existing image properties or add new "
500 023e1217 Nikos Skalkotos
            "ones. Be careful! Most properties have special meaning and "
501 023e1217 Nikos Skalkotos
            "alter the image deployment behaviour. Press <HELP> to see more "
502 023e1217 Nikos Skalkotos
            "information about image properties. Press <BACK> when done.",
503 023e1217 Nikos Skalkotos
            height=18, width=WIDTH, choices=choices, menu_height=10,
504 023e1217 Nikos Skalkotos
            ok_label="Edit", extra_button=1, extra_label="Add", cancel="Back",
505 023e1217 Nikos Skalkotos
            help_button=1, title="Image Properties")
506 023e1217 Nikos Skalkotos
507 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
508 023e1217 Nikos Skalkotos
            return True
509 023e1217 Nikos Skalkotos
        # Edit button
510 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_OK:
511 023e1217 Nikos Skalkotos
            (code, answer) = d.inputbox("Please provide a new value for the "
512 023e1217 Nikos Skalkotos
                                        "image property with name `%s':" %
513 023e1217 Nikos Skalkotos
                                        choice,
514 023e1217 Nikos Skalkotos
                                        init=session['metadata'][choice],
515 023e1217 Nikos Skalkotos
                                        width=WIDTH)
516 023e1217 Nikos Skalkotos
            if code not in (d.DIALOG_CANCEL, d.DIALOG_ESC):
517 023e1217 Nikos Skalkotos
                value = answer.strip()
518 023e1217 Nikos Skalkotos
                if len(value) == 0:
519 023e1217 Nikos Skalkotos
                    d.msgbox("Value cannot be empty!")
520 023e1217 Nikos Skalkotos
                    continue
521 023e1217 Nikos Skalkotos
                else:
522 023e1217 Nikos Skalkotos
                    session['metadata'][choice] = value
523 023e1217 Nikos Skalkotos
        # ADD button
524 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_EXTRA:
525 023e1217 Nikos Skalkotos
            add_property(session)
526 023e1217 Nikos Skalkotos
        elif code == 'help':
527 023e1217 Nikos Skalkotos
            help_file = get_help_file("image_properties")
528 023e1217 Nikos Skalkotos
            assert os.path.exists(help_file)
529 023e1217 Nikos Skalkotos
            d.textbox(help_file, title="Image Properties", width=70, height=40)
530 023e1217 Nikos Skalkotos
531 023e1217 Nikos Skalkotos
532 023e1217 Nikos Skalkotos
def delete_properties(session):
533 88f83027 Nikos Skalkotos
    """Delete an image property"""
534 023e1217 Nikos Skalkotos
    d = session['dialog']
535 023e1217 Nikos Skalkotos
536 023e1217 Nikos Skalkotos
    choices = []
537 023e1217 Nikos Skalkotos
    for (key, val) in session['metadata'].items():
538 023e1217 Nikos Skalkotos
        choices.append((key, "%s" % val, 0))
539 023e1217 Nikos Skalkotos
540 023e1217 Nikos Skalkotos
    (code, to_delete) = d.checklist("Choose which properties to delete:",
541 023e1217 Nikos Skalkotos
                                    choices=choices, width=WIDTH)
542 5e18a927 Nikos Skalkotos
    to_delete = map(lambda x: x.strip('"'), to_delete)  # needed for OpenSUSE
543 023e1217 Nikos Skalkotos
544 023e1217 Nikos Skalkotos
    # If the user exits with ESC or CANCEL, the returned tag list is empty.
545 023e1217 Nikos Skalkotos
    for i in to_delete:
546 023e1217 Nikos Skalkotos
        del session['metadata'][i]
547 023e1217 Nikos Skalkotos
548 023e1217 Nikos Skalkotos
    cnt = len(to_delete)
549 023e1217 Nikos Skalkotos
    if cnt > 0:
550 023e1217 Nikos Skalkotos
        d.msgbox("%d image properties were deleted." % cnt, width=SMALL_WIDTH)
551 023e1217 Nikos Skalkotos
        return True
552 023e1217 Nikos Skalkotos
    else:
553 023e1217 Nikos Skalkotos
        return False
554 023e1217 Nikos Skalkotos
555 023e1217 Nikos Skalkotos
556 023e1217 Nikos Skalkotos
def exclude_tasks(session):
557 88f83027 Nikos Skalkotos
    """Exclude specific tasks from running during image deployment"""
558 023e1217 Nikos Skalkotos
    d = session['dialog']
559 023e1217 Nikos Skalkotos
560 023e1217 Nikos Skalkotos
    index = 0
561 023e1217 Nikos Skalkotos
    displayed_index = 1
562 023e1217 Nikos Skalkotos
    choices = []
563 023e1217 Nikos Skalkotos
    mapping = {}
564 023e1217 Nikos Skalkotos
    if 'excluded_tasks' not in session:
565 023e1217 Nikos Skalkotos
        session['excluded_tasks'] = []
566 023e1217 Nikos Skalkotos
567 023e1217 Nikos Skalkotos
    if -1 in session['excluded_tasks']:
568 023e1217 Nikos Skalkotos
        if not d.yesno("Image deployment configuration is disabled. "
569 023e1217 Nikos Skalkotos
                       "Do you wish to enable it?", width=SMALL_WIDTH):
570 023e1217 Nikos Skalkotos
            session['excluded_tasks'].remove(-1)
571 023e1217 Nikos Skalkotos
        else:
572 023e1217 Nikos Skalkotos
            return False
573 023e1217 Nikos Skalkotos
574 023e1217 Nikos Skalkotos
    for (msg, task, osfamily) in CONFIGURATION_TASKS:
575 023e1217 Nikos Skalkotos
        if session['metadata']['OSFAMILY'] in osfamily:
576 023e1217 Nikos Skalkotos
            checked = 1 if index in session['excluded_tasks'] else 0
577 023e1217 Nikos Skalkotos
            choices.append((str(displayed_index), msg, checked))
578 023e1217 Nikos Skalkotos
            mapping[displayed_index] = index
579 023e1217 Nikos Skalkotos
            displayed_index += 1
580 023e1217 Nikos Skalkotos
        index += 1
581 023e1217 Nikos Skalkotos
582 023e1217 Nikos Skalkotos
    while 1:
583 023e1217 Nikos Skalkotos
        (code, tags) = d.checklist(
584 023e1217 Nikos Skalkotos
            text="Please choose which configuration tasks you would like to "
585 023e1217 Nikos Skalkotos
                 "prevent from running during image deployment. "
586 023e1217 Nikos Skalkotos
                 "Press <No Config> to supress any configuration. "
587 023e1217 Nikos Skalkotos
                 "Press <Help> for more help on the image deployment "
588 023e1217 Nikos Skalkotos
                 "configuration tasks.",
589 023e1217 Nikos Skalkotos
            choices=choices, height=19, list_height=8, width=WIDTH,
590 023e1217 Nikos Skalkotos
            help_button=1, extra_button=1, extra_label="No Config",
591 023e1217 Nikos Skalkotos
            title="Exclude Configuration Tasks")
592 5e18a927 Nikos Skalkotos
        tags = map(lambda x: x.strip('"'), tags)  # Needed for OpenSUSE
593 023e1217 Nikos Skalkotos
594 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
595 023e1217 Nikos Skalkotos
            return False
596 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_HELP:
597 023e1217 Nikos Skalkotos
            help_file = get_help_file("configuration_tasks")
598 023e1217 Nikos Skalkotos
            assert os.path.exists(help_file)
599 023e1217 Nikos Skalkotos
            d.textbox(help_file, title="Configuration Tasks",
600 023e1217 Nikos Skalkotos
                      width=70, height=40)
601 023e1217 Nikos Skalkotos
        # No Config button
602 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_EXTRA:
603 023e1217 Nikos Skalkotos
            session['excluded_tasks'] = [-1]
604 023e1217 Nikos Skalkotos
            session['task_metadata'] = ["EXCLUDE_ALL_TASKS"]
605 023e1217 Nikos Skalkotos
            break
606 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_OK:
607 023e1217 Nikos Skalkotos
            session['excluded_tasks'] = []
608 023e1217 Nikos Skalkotos
            for tag in tags:
609 023e1217 Nikos Skalkotos
                session['excluded_tasks'].append(mapping[int(tag)])
610 023e1217 Nikos Skalkotos
611 023e1217 Nikos Skalkotos
            exclude_metadata = []
612 023e1217 Nikos Skalkotos
            for task in session['excluded_tasks']:
613 023e1217 Nikos Skalkotos
                exclude_metadata.extend(CONFIGURATION_TASKS[task][1])
614 023e1217 Nikos Skalkotos
615 023e1217 Nikos Skalkotos
            session['task_metadata'] = map(lambda x: "EXCLUDE_TASK_%s" % x,
616 023e1217 Nikos Skalkotos
                                           exclude_metadata)
617 023e1217 Nikos Skalkotos
            break
618 023e1217 Nikos Skalkotos
619 023e1217 Nikos Skalkotos
    return True
620 023e1217 Nikos Skalkotos
621 023e1217 Nikos Skalkotos
622 0eac0256 Nikos Skalkotos
def sysprep_params(session):
623 0eac0256 Nikos Skalkotos
624 0eac0256 Nikos Skalkotos
    d = session['dialog']
625 0eac0256 Nikos Skalkotos
    image = session['image']
626 0eac0256 Nikos Skalkotos
627 0eac0256 Nikos Skalkotos
    available = image.os.sysprep_params
628 0eac0256 Nikos Skalkotos
    needed = image.os.needed_sysprep_params()
629 0eac0256 Nikos Skalkotos
630 0eac0256 Nikos Skalkotos
    if len(needed) == 0:
631 0eac0256 Nikos Skalkotos
        return True
632 0eac0256 Nikos Skalkotos
633 0eac0256 Nikos Skalkotos
    fields = []
634 0eac0256 Nikos Skalkotos
    for param in needed:
635 0eac0256 Nikos Skalkotos
        default = available[param.name] if param.name in available else ""
636 0eac0256 Nikos Skalkotos
        fields.append(("%s: " % param.description, default, param.length))
637 0eac0256 Nikos Skalkotos
638 0eac0256 Nikos Skalkotos
    txt = "Please provide the following system preparation parameters:"
639 0eac0256 Nikos Skalkotos
    code, output = d.form(txt, height=13, width=WIDTH, form_height=len(fields),
640 0eac0256 Nikos Skalkotos
                          fields=fields)
641 0eac0256 Nikos Skalkotos
642 0eac0256 Nikos Skalkotos
    if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
643 0eac0256 Nikos Skalkotos
        return False
644 0eac0256 Nikos Skalkotos
645 0eac0256 Nikos Skalkotos
    sysprep_params = {}
646 0eac0256 Nikos Skalkotos
    for i in range(len(fields)):
647 0eac0256 Nikos Skalkotos
        if needed[i].validator(output[i]):
648 0eac0256 Nikos Skalkotos
            image.os.sysprep_params[needed[i].name] = output[i]
649 0eac0256 Nikos Skalkotos
        else:
650 0eac0256 Nikos Skalkotos
            d.msgbox("The value you provided for parameter: %s is not valid" %
651 0eac0256 Nikos Skalkotos
                     name, width=SMALL_WIDTH)
652 0eac0256 Nikos Skalkotos
            return False
653 0eac0256 Nikos Skalkotos
654 0eac0256 Nikos Skalkotos
    return True
655 0eac0256 Nikos Skalkotos
656 0eac0256 Nikos Skalkotos
657 023e1217 Nikos Skalkotos
def sysprep(session):
658 88f83027 Nikos Skalkotos
    """Perform various system preperation tasks on the image"""
659 023e1217 Nikos Skalkotos
    d = session['dialog']
660 f5174d2c Nikos Skalkotos
    image = session['image']
661 023e1217 Nikos Skalkotos
662 023e1217 Nikos Skalkotos
    # Is the image already shrinked?
663 023e1217 Nikos Skalkotos
    if 'shrinked' in session and session['shrinked']:
664 023e1217 Nikos Skalkotos
        msg = "It seems you have shrinked the image. Running system " \
665 023e1217 Nikos Skalkotos
              "preparation tasks on a shrinked image is dangerous."
666 023e1217 Nikos Skalkotos
667 023e1217 Nikos Skalkotos
        if d.yesno("%s\n\nDo you really want to continue?" % msg,
668 023e1217 Nikos Skalkotos
                   width=SMALL_WIDTH, defaultno=1):
669 023e1217 Nikos Skalkotos
            return
670 023e1217 Nikos Skalkotos
671 023e1217 Nikos Skalkotos
    wrapper = textwrap.TextWrapper(width=WIDTH - 5)
672 023e1217 Nikos Skalkotos
673 fa65eda1 Nikos Skalkotos
    syspreps = image.os.list_syspreps()
674 023e1217 Nikos Skalkotos
675 023e1217 Nikos Skalkotos
    if len(syspreps) == 0:
676 023e1217 Nikos Skalkotos
        d.msgbox("No system preparation task available to run!",
677 023e1217 Nikos Skalkotos
                 title="System Preperation", width=SMALL_WIDTH)
678 023e1217 Nikos Skalkotos
        return
679 023e1217 Nikos Skalkotos
680 023e1217 Nikos Skalkotos
    while 1:
681 023e1217 Nikos Skalkotos
        choices = []
682 023e1217 Nikos Skalkotos
        index = 0
683 497fadb3 Nikos Skalkotos
684 497fadb3 Nikos Skalkotos
        help_title = "System Preperation Tasks"
685 497fadb3 Nikos Skalkotos
        sysprep_help = "%s\n%s\n\n" % (help_title, '=' * len(help_title))
686 497fadb3 Nikos Skalkotos
687 023e1217 Nikos Skalkotos
        for sysprep in syspreps:
688 f5174d2c Nikos Skalkotos
            name, descr = image.os.sysprep_info(sysprep)
689 023e1217 Nikos Skalkotos
            display_name = name.replace('-', ' ').capitalize()
690 023e1217 Nikos Skalkotos
            sysprep_help += "%s\n" % display_name
691 023e1217 Nikos Skalkotos
            sysprep_help += "%s\n" % ('-' * len(display_name))
692 023e1217 Nikos Skalkotos
            sysprep_help += "%s\n\n" % wrapper.fill(" ".join(descr.split()))
693 023e1217 Nikos Skalkotos
            enabled = 1 if sysprep.enabled else 0
694 023e1217 Nikos Skalkotos
            choices.append((str(index + 1), display_name, enabled))
695 023e1217 Nikos Skalkotos
            index += 1
696 023e1217 Nikos Skalkotos
697 023e1217 Nikos Skalkotos
        (code, tags) = d.checklist(
698 023e1217 Nikos Skalkotos
            "Please choose which system preparation tasks you would like to "
699 023e1217 Nikos Skalkotos
            "run on the image. Press <Help> to see details about the system "
700 023e1217 Nikos Skalkotos
            "preparation tasks.", title="Run system preparation tasks",
701 023e1217 Nikos Skalkotos
            choices=choices, width=70, ok_label="Run", help_button=1)
702 5e18a927 Nikos Skalkotos
        tags = map(lambda x: x.strip('"'), tags)  # Needed for OpenSUSE
703 023e1217 Nikos Skalkotos
704 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
705 023e1217 Nikos Skalkotos
            return False
706 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_HELP:
707 023e1217 Nikos Skalkotos
            d.scrollbox(sysprep_help, width=WIDTH)
708 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_OK:
709 023e1217 Nikos Skalkotos
            # Enable selected syspreps and disable the rest
710 023e1217 Nikos Skalkotos
            for i in range(len(syspreps)):
711 023e1217 Nikos Skalkotos
                if str(i + 1) in tags:
712 f5174d2c Nikos Skalkotos
                    image.os.enable_sysprep(syspreps[i])
713 023e1217 Nikos Skalkotos
                else:
714 f5174d2c Nikos Skalkotos
                    image.os.disable_sysprep(syspreps[i])
715 023e1217 Nikos Skalkotos
716 fa65eda1 Nikos Skalkotos
            if len([s for s in image.os.list_syspreps() if s.enabled]) == 0:
717 fa65eda1 Nikos Skalkotos
                d.msgbox("No system preperation task is selected!",
718 fa65eda1 Nikos Skalkotos
                         title="System Preperation", width=SMALL_WIDTH)
719 fa65eda1 Nikos Skalkotos
                continue
720 fa65eda1 Nikos Skalkotos
721 0eac0256 Nikos Skalkotos
            if not sysprep_params(session):
722 0eac0256 Nikos Skalkotos
                continue
723 0eac0256 Nikos Skalkotos
724 023e1217 Nikos Skalkotos
            infobox = InfoBoxOutput(d, "Image Configuration")
725 023e1217 Nikos Skalkotos
            try:
726 f5174d2c Nikos Skalkotos
                image.out.add(infobox)
727 023e1217 Nikos Skalkotos
                try:
728 71b0ab28 Nikos Skalkotos
                    # The checksum is invalid. We have mounted the image rw
729 71b0ab28 Nikos Skalkotos
                    if 'checksum' in session:
730 71b0ab28 Nikos Skalkotos
                        del session['checksum']
731 71b0ab28 Nikos Skalkotos
732 71b0ab28 Nikos Skalkotos
                    # Monitor the metadata changes during syspreps
733 71b0ab28 Nikos Skalkotos
                    with MetadataMonitor(session, image.os.meta):
734 71b0ab28 Nikos Skalkotos
                        try:
735 f5174d2c Nikos Skalkotos
                            image.os.do_sysprep()
736 023e1217 Nikos Skalkotos
                            infobox.finalize()
737 71b0ab28 Nikos Skalkotos
                        except FatalError as e:
738 71b0ab28 Nikos Skalkotos
                            title = "System Preparation"
739 71b0ab28 Nikos Skalkotos
                            d.msgbox("System Preparation failed: %s" % e,
740 71b0ab28 Nikos Skalkotos
                                     title=title, width=SMALL_WIDTH)
741 023e1217 Nikos Skalkotos
                finally:
742 f5174d2c Nikos Skalkotos
                    image.out.remove(infobox)
743 023e1217 Nikos Skalkotos
            finally:
744 023e1217 Nikos Skalkotos
                infobox.cleanup()
745 023e1217 Nikos Skalkotos
            break
746 023e1217 Nikos Skalkotos
    return True
747 023e1217 Nikos Skalkotos
748 023e1217 Nikos Skalkotos
749 023e1217 Nikos Skalkotos
def shrink(session):
750 88f83027 Nikos Skalkotos
    """Shrink the image"""
751 023e1217 Nikos Skalkotos
    d = session['dialog']
752 f5174d2c Nikos Skalkotos
    image = session['image']
753 023e1217 Nikos Skalkotos
754 023e1217 Nikos Skalkotos
    shrinked = 'shrinked' in session and session['shrinked']
755 023e1217 Nikos Skalkotos
756 023e1217 Nikos Skalkotos
    if shrinked:
757 023e1217 Nikos Skalkotos
        d.msgbox("The image is already shrinked!", title="Image Shrinking",
758 023e1217 Nikos Skalkotos
                 width=SMALL_WIDTH)
759 023e1217 Nikos Skalkotos
        return True
760 023e1217 Nikos Skalkotos
761 023e1217 Nikos Skalkotos
    msg = "This operation will shrink the last partition of the image to " \
762 023e1217 Nikos Skalkotos
          "reduce the total image size. If the last partition is a swap " \
763 023e1217 Nikos Skalkotos
          "partition, then this partition is removed and the partition " \
764 023e1217 Nikos Skalkotos
          "before that is shrinked. The removed swap partition will be " \
765 023e1217 Nikos Skalkotos
          "recreated during image deployment."
766 023e1217 Nikos Skalkotos
767 023e1217 Nikos Skalkotos
    if not d.yesno("%s\n\nDo you want to continue?" % msg, width=WIDTH,
768 023e1217 Nikos Skalkotos
                   height=12, title="Image Shrinking"):
769 f5174d2c Nikos Skalkotos
        with MetadataMonitor(session, image.meta):
770 023e1217 Nikos Skalkotos
            infobox = InfoBoxOutput(d, "Image Shrinking", height=4)
771 f5174d2c Nikos Skalkotos
            image.out.add(infobox)
772 023e1217 Nikos Skalkotos
            try:
773 f5174d2c Nikos Skalkotos
                image.shrink()
774 023e1217 Nikos Skalkotos
                infobox.finalize()
775 023e1217 Nikos Skalkotos
            finally:
776 f5174d2c Nikos Skalkotos
                image.out.remove(infobox)
777 023e1217 Nikos Skalkotos
778 023e1217 Nikos Skalkotos
        session['shrinked'] = True
779 023e1217 Nikos Skalkotos
        update_background_title(session)
780 023e1217 Nikos Skalkotos
    else:
781 023e1217 Nikos Skalkotos
        return False
782 023e1217 Nikos Skalkotos
783 023e1217 Nikos Skalkotos
    return True
784 023e1217 Nikos Skalkotos
785 023e1217 Nikos Skalkotos
786 023e1217 Nikos Skalkotos
def customization_menu(session):
787 88f83027 Nikos Skalkotos
    """Show image customization menu"""
788 023e1217 Nikos Skalkotos
    d = session['dialog']
789 023e1217 Nikos Skalkotos
790 023e1217 Nikos Skalkotos
    choices = [("Sysprep", "Run various image preparation tasks"),
791 023e1217 Nikos Skalkotos
               ("Shrink", "Shrink image"),
792 023e1217 Nikos Skalkotos
               ("View/Modify", "View/Modify image properties"),
793 023e1217 Nikos Skalkotos
               ("Delete", "Delete image properties"),
794 023e1217 Nikos Skalkotos
               ("Exclude", "Exclude various deployment tasks from running")]
795 023e1217 Nikos Skalkotos
796 023e1217 Nikos Skalkotos
    default_item = 0
797 023e1217 Nikos Skalkotos
798 023e1217 Nikos Skalkotos
    actions = {"Sysprep": sysprep,
799 023e1217 Nikos Skalkotos
               "Shrink": shrink,
800 023e1217 Nikos Skalkotos
               "View/Modify": modify_properties,
801 023e1217 Nikos Skalkotos
               "Delete": delete_properties,
802 023e1217 Nikos Skalkotos
               "Exclude": exclude_tasks}
803 023e1217 Nikos Skalkotos
    while 1:
804 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
805 023e1217 Nikos Skalkotos
            text="Choose one of the following or press <Back> to exit.",
806 023e1217 Nikos Skalkotos
            width=WIDTH, choices=choices, cancel="Back", height=13,
807 023e1217 Nikos Skalkotos
            menu_height=len(choices), default_item=choices[default_item][0],
808 023e1217 Nikos Skalkotos
            title="Image Customization Menu")
809 023e1217 Nikos Skalkotos
810 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
811 023e1217 Nikos Skalkotos
            break
812 023e1217 Nikos Skalkotos
        elif choice in actions:
813 023e1217 Nikos Skalkotos
            default_item = [entry[0] for entry in choices].index(choice)
814 023e1217 Nikos Skalkotos
            if actions[choice](session):
815 023e1217 Nikos Skalkotos
                default_item = (default_item + 1) % len(choices)
816 023e1217 Nikos Skalkotos
817 023e1217 Nikos Skalkotos
818 023e1217 Nikos Skalkotos
def main_menu(session):
819 88f83027 Nikos Skalkotos
    """Show the main menu of the program"""
820 023e1217 Nikos Skalkotos
    d = session['dialog']
821 023e1217 Nikos Skalkotos
822 023e1217 Nikos Skalkotos
    update_background_title(session)
823 023e1217 Nikos Skalkotos
824 49c07ce3 Nikos Skalkotos
    choices = [("Customize", "Customize image & cloud deployment options"),
825 49c07ce3 Nikos Skalkotos
               ("Register", "Register image to a cloud"),
826 023e1217 Nikos Skalkotos
               ("Extract", "Dump image to local file system"),
827 023e1217 Nikos Skalkotos
               ("Reset", "Reset everything and start over again"),
828 023e1217 Nikos Skalkotos
               ("Help", "Get help for using snf-image-creator")]
829 023e1217 Nikos Skalkotos
830 023e1217 Nikos Skalkotos
    default_item = "Customize"
831 023e1217 Nikos Skalkotos
832 023e1217 Nikos Skalkotos
    actions = {"Customize": customization_menu, "Register": kamaki_menu,
833 023e1217 Nikos Skalkotos
               "Extract": extract_image}
834 023e1217 Nikos Skalkotos
    while 1:
835 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
836 023e1217 Nikos Skalkotos
            text="Choose one of the following or press <Exit> to exit.",
837 023e1217 Nikos Skalkotos
            width=WIDTH, choices=choices, cancel="Exit", height=13,
838 023e1217 Nikos Skalkotos
            default_item=default_item, menu_height=len(choices),
839 ffc64d7c Nikos Skalkotos
            title="Image Creator for synnefo (snf-image-creator version %s)" %
840 023e1217 Nikos Skalkotos
                  version)
841 023e1217 Nikos Skalkotos
842 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
843 023e1217 Nikos Skalkotos
            if confirm_exit(d):
844 023e1217 Nikos Skalkotos
                break
845 023e1217 Nikos Skalkotos
        elif choice == "Reset":
846 023e1217 Nikos Skalkotos
            if confirm_reset(d):
847 34e7a04a Nikos Skalkotos
                d.infobox("Resetting snf-image-creator. Please wait ...",
848 023e1217 Nikos Skalkotos
                          width=SMALL_WIDTH)
849 023e1217 Nikos Skalkotos
                raise Reset
850 aa04fb4e Nikos Skalkotos
        elif choice == "Help":
851 aa04fb4e Nikos Skalkotos
            d.msgbox("For help, check the online documentation:\n\nhttp://www"
852 aa04fb4e Nikos Skalkotos
                     ".synnefo.org/docs/snf-image-creator/latest/",
853 aa04fb4e Nikos Skalkotos
                     width=WIDTH, title="Help")
854 023e1217 Nikos Skalkotos
        elif choice in actions:
855 023e1217 Nikos Skalkotos
            actions[choice](session)
856 023e1217 Nikos Skalkotos
857 023e1217 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :