Statistics
| Branch: | Tag: | Revision:

root / image_creator / dialog_menu.py @ f953c647

History | View | Annotate | Download (33.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 47505e53 Nikos Skalkotos
SYSPREP_PARAM_MAXLEN = 20
72 023e1217 Nikos Skalkotos
73 82e8c357 Nikos Skalkotos
74 61d14323 Nikos Skalkotos
class MetadataMonitor(object):
75 88f83027 Nikos Skalkotos
    """Monitors image metadata chages"""
76 023e1217 Nikos Skalkotos
    def __init__(self, session, meta):
77 023e1217 Nikos Skalkotos
        self.session = session
78 023e1217 Nikos Skalkotos
        self.meta = meta
79 023e1217 Nikos Skalkotos
80 023e1217 Nikos Skalkotos
    def __enter__(self):
81 023e1217 Nikos Skalkotos
        self.old = {}
82 023e1217 Nikos Skalkotos
        for (k, v) in self.meta.items():
83 023e1217 Nikos Skalkotos
            self.old[k] = v
84 023e1217 Nikos Skalkotos
85 023e1217 Nikos Skalkotos
    def __exit__(self, type, value, traceback):
86 023e1217 Nikos Skalkotos
        d = self.session['dialog']
87 023e1217 Nikos Skalkotos
88 023e1217 Nikos Skalkotos
        altered = {}
89 023e1217 Nikos Skalkotos
        added = {}
90 023e1217 Nikos Skalkotos
91 023e1217 Nikos Skalkotos
        for (k, v) in self.meta.items():
92 023e1217 Nikos Skalkotos
            if k not in self.old:
93 023e1217 Nikos Skalkotos
                added[k] = v
94 023e1217 Nikos Skalkotos
            elif self.old[k] != v:
95 023e1217 Nikos Skalkotos
                altered[k] = v
96 023e1217 Nikos Skalkotos
97 023e1217 Nikos Skalkotos
        if not (len(added) or len(altered)):
98 023e1217 Nikos Skalkotos
            return
99 023e1217 Nikos Skalkotos
100 023e1217 Nikos Skalkotos
        msg = "The last action has changed some image properties:\n\n"
101 023e1217 Nikos Skalkotos
        if len(added):
102 023e1217 Nikos Skalkotos
            msg += "New image properties:\n"
103 023e1217 Nikos Skalkotos
            for (k, v) in added.items():
104 023e1217 Nikos Skalkotos
                msg += '    %s: "%s"\n' % (k, v)
105 023e1217 Nikos Skalkotos
            msg += "\n"
106 023e1217 Nikos Skalkotos
        if len(altered):
107 023e1217 Nikos Skalkotos
            msg += "Updated image properties:\n"
108 023e1217 Nikos Skalkotos
            for (k, v) in altered.items():
109 023e1217 Nikos Skalkotos
                msg += '    %s: "%s" -> "%s"\n' % (k, self.old[k], v)
110 023e1217 Nikos Skalkotos
            msg += "\n"
111 023e1217 Nikos Skalkotos
112 023e1217 Nikos Skalkotos
        self.session['metadata'].update(added)
113 023e1217 Nikos Skalkotos
        self.session['metadata'].update(altered)
114 023e1217 Nikos Skalkotos
        d.msgbox(msg, title="Image Property Changes", width=SMALL_WIDTH)
115 023e1217 Nikos Skalkotos
116 023e1217 Nikos Skalkotos
117 023e1217 Nikos Skalkotos
def upload_image(session):
118 ffc64d7c Nikos Skalkotos
    """Upload the image to the storage service"""
119 023e1217 Nikos Skalkotos
    d = session["dialog"]
120 f5174d2c Nikos Skalkotos
    image = session['image']
121 66719e36 Nikos Skalkotos
    meta = session['metadata']
122 f5174d2c Nikos Skalkotos
    size = image.size
123 023e1217 Nikos Skalkotos
124 023e1217 Nikos Skalkotos
    if "account" not in session:
125 49c07ce3 Nikos Skalkotos
        d.msgbox("You need to select a valid cloud before you can upload "
126 ffc64d7c Nikos Skalkotos
                 "images to it", width=SMALL_WIDTH)
127 023e1217 Nikos Skalkotos
        return False
128 023e1217 Nikos Skalkotos
129 023e1217 Nikos Skalkotos
    while 1:
130 66719e36 Nikos Skalkotos
        if 'upload' in session:
131 66719e36 Nikos Skalkotos
            init = session['upload']
132 66719e36 Nikos Skalkotos
        elif 'OS' in meta:
133 66719e36 Nikos Skalkotos
            init = "%s.diskdump" % meta['OS']
134 66719e36 Nikos Skalkotos
        else:
135 66719e36 Nikos Skalkotos
            init = ""
136 023e1217 Nikos Skalkotos
        (code, answer) = d.inputbox("Please provide a filename:", init=init,
137 023e1217 Nikos Skalkotos
                                    width=WIDTH)
138 023e1217 Nikos Skalkotos
139 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
140 023e1217 Nikos Skalkotos
            return False
141 023e1217 Nikos Skalkotos
142 023e1217 Nikos Skalkotos
        filename = answer.strip()
143 023e1217 Nikos Skalkotos
        if len(filename) == 0:
144 023e1217 Nikos Skalkotos
            d.msgbox("Filename cannot be empty", width=SMALL_WIDTH)
145 023e1217 Nikos Skalkotos
            continue
146 03eb7dc8 Nikos Skalkotos
147 03eb7dc8 Nikos Skalkotos
        kamaki = Kamaki(session['account'], None)
148 03eb7dc8 Nikos Skalkotos
        overwrite = []
149 03eb7dc8 Nikos Skalkotos
        for f in (filename, "%s.md5sum" % filename, "%s.meta" % filename):
150 03eb7dc8 Nikos Skalkotos
            if kamaki.object_exists(f):
151 03eb7dc8 Nikos Skalkotos
                overwrite.append(f)
152 03eb7dc8 Nikos Skalkotos
153 03eb7dc8 Nikos Skalkotos
        if len(overwrite) > 0:
154 ffc64d7c Nikos Skalkotos
            if d.yesno("The following storage service object(s) already "
155 ffc64d7c Nikos Skalkotos
                       "exist(s):\n%s\nDo you want to overwrite them?" %
156 03eb7dc8 Nikos Skalkotos
                       "\n".join(overwrite), width=WIDTH, defaultno=1):
157 03eb7dc8 Nikos Skalkotos
                continue
158 03eb7dc8 Nikos Skalkotos
159 023e1217 Nikos Skalkotos
        session['upload'] = filename
160 023e1217 Nikos Skalkotos
        break
161 023e1217 Nikos Skalkotos
162 34e7a04a Nikos Skalkotos
    gauge = GaugeOutput(d, "Image Upload", "Uploading ...")
163 023e1217 Nikos Skalkotos
    try:
164 f5174d2c Nikos Skalkotos
        out = image.out
165 023e1217 Nikos Skalkotos
        out.add(gauge)
166 03eb7dc8 Nikos Skalkotos
        kamaki.out = out
167 023e1217 Nikos Skalkotos
        try:
168 023e1217 Nikos Skalkotos
            if 'checksum' not in session:
169 023e1217 Nikos Skalkotos
                md5 = MD5(out)
170 f5174d2c Nikos Skalkotos
                session['checksum'] = md5.compute(image.device, size)
171 023e1217 Nikos Skalkotos
172 023e1217 Nikos Skalkotos
            try:
173 023e1217 Nikos Skalkotos
                # Upload image file
174 f5174d2c Nikos Skalkotos
                with open(image.device, 'rb') as f:
175 023e1217 Nikos Skalkotos
                    session["pithos_uri"] = \
176 023e1217 Nikos Skalkotos
                        kamaki.upload(f, size, filename,
177 023e1217 Nikos Skalkotos
                                      "Calculating block hashes",
178 023e1217 Nikos Skalkotos
                                      "Uploading missing blocks")
179 023e1217 Nikos Skalkotos
                # Upload md5sum file
180 34e7a04a Nikos Skalkotos
                out.output("Uploading md5sum file ...")
181 023e1217 Nikos Skalkotos
                md5str = "%s %s\n" % (session['checksum'], filename)
182 023e1217 Nikos Skalkotos
                kamaki.upload(StringIO.StringIO(md5str), size=len(md5str),
183 023e1217 Nikos Skalkotos
                              remote_path="%s.md5sum" % filename)
184 023e1217 Nikos Skalkotos
                out.success("done")
185 023e1217 Nikos Skalkotos
186 023e1217 Nikos Skalkotos
            except ClientError as e:
187 ffc64d7c Nikos Skalkotos
                d.msgbox(
188 ffc64d7c Nikos Skalkotos
                    "Error in storage service client: %s" % e.message,
189 ffc64d7c Nikos Skalkotos
                    title="Storage Service Client Error", width=SMALL_WIDTH)
190 023e1217 Nikos Skalkotos
                if 'pithos_uri' in session:
191 023e1217 Nikos Skalkotos
                    del session['pithos_uri']
192 023e1217 Nikos Skalkotos
                return False
193 023e1217 Nikos Skalkotos
        finally:
194 023e1217 Nikos Skalkotos
            out.remove(gauge)
195 023e1217 Nikos Skalkotos
    finally:
196 023e1217 Nikos Skalkotos
        gauge.cleanup()
197 023e1217 Nikos Skalkotos
198 ffc64d7c Nikos Skalkotos
    d.msgbox("Image file `%s' was successfully uploaded" % filename,
199 023e1217 Nikos Skalkotos
             width=SMALL_WIDTH)
200 023e1217 Nikos Skalkotos
201 023e1217 Nikos Skalkotos
    return True
202 023e1217 Nikos Skalkotos
203 023e1217 Nikos Skalkotos
204 023e1217 Nikos Skalkotos
def register_image(session):
205 ffc64d7c Nikos Skalkotos
    """Register image with the compute service"""
206 023e1217 Nikos Skalkotos
    d = session["dialog"]
207 023e1217 Nikos Skalkotos
208 37d581b8 Nikos Skalkotos
    is_public = False
209 37d581b8 Nikos Skalkotos
210 023e1217 Nikos Skalkotos
    if "account" not in session:
211 49c07ce3 Nikos Skalkotos
        d.msgbox("You need to select a valid cloud before you "
212 ffc64d7c Nikos Skalkotos
                 "can register an images with it", width=SMALL_WIDTH)
213 023e1217 Nikos Skalkotos
        return False
214 023e1217 Nikos Skalkotos
215 023e1217 Nikos Skalkotos
    if "pithos_uri" not in session:
216 ffc64d7c Nikos Skalkotos
        d.msgbox("You need to upload the image to the cloud before you can "
217 ffc64d7c Nikos Skalkotos
                 "register it", width=SMALL_WIDTH)
218 023e1217 Nikos Skalkotos
        return False
219 023e1217 Nikos Skalkotos
220 6b7eb528 Nikos Skalkotos
    name = ""
221 6b7eb528 Nikos Skalkotos
    description = session['metadata']['DESCRIPTION'] if 'DESCRIPTION' in \
222 6b7eb528 Nikos Skalkotos
        session['metadata'] else ""
223 6b7eb528 Nikos Skalkotos
224 023e1217 Nikos Skalkotos
    while 1:
225 6b7eb528 Nikos Skalkotos
        fields = [
226 6b7eb528 Nikos Skalkotos
            ("Registration name:", name, 60),
227 6b7eb528 Nikos Skalkotos
            ("Description (optional):", description, 80)]
228 6b7eb528 Nikos Skalkotos
229 6b7eb528 Nikos Skalkotos
        (code, output) = d.form(
230 6b7eb528 Nikos Skalkotos
            "Please provide the following registration info:", height=11,
231 6b7eb528 Nikos Skalkotos
            width=WIDTH, form_height=2, fields=fields)
232 6b7eb528 Nikos Skalkotos
233 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
234 023e1217 Nikos Skalkotos
            return False
235 023e1217 Nikos Skalkotos
236 6b7eb528 Nikos Skalkotos
        name, description = output
237 6b7eb528 Nikos Skalkotos
        name = name.strip()
238 6b7eb528 Nikos Skalkotos
        description = description.strip()
239 6b7eb528 Nikos Skalkotos
240 023e1217 Nikos Skalkotos
        if len(name) == 0:
241 023e1217 Nikos Skalkotos
            d.msgbox("Registration name cannot be empty", width=SMALL_WIDTH)
242 023e1217 Nikos Skalkotos
            continue
243 37d581b8 Nikos Skalkotos
244 66719e36 Nikos Skalkotos
        ret = d.yesno("Make the image public?\\nA public image is accessible "
245 37d581b8 Nikos Skalkotos
                      "by every user of the service.", defaultno=1,
246 37d581b8 Nikos Skalkotos
                      width=WIDTH)
247 37d581b8 Nikos Skalkotos
        if ret not in (0, 1):
248 37d581b8 Nikos Skalkotos
            continue
249 37d581b8 Nikos Skalkotos
250 37d581b8 Nikos Skalkotos
        is_public = True if ret == 0 else False
251 37d581b8 Nikos Skalkotos
252 023e1217 Nikos Skalkotos
        break
253 023e1217 Nikos Skalkotos
254 6b7eb528 Nikos Skalkotos
    session['metadata']['DESCRIPTION'] = description
255 023e1217 Nikos Skalkotos
    metadata = {}
256 023e1217 Nikos Skalkotos
    metadata.update(session['metadata'])
257 023e1217 Nikos Skalkotos
    if 'task_metadata' in session:
258 023e1217 Nikos Skalkotos
        for key in session['task_metadata']:
259 023e1217 Nikos Skalkotos
            metadata[key] = 'yes'
260 023e1217 Nikos Skalkotos
261 37d581b8 Nikos Skalkotos
    img_type = "public" if is_public else "private"
262 34e7a04a Nikos Skalkotos
    gauge = GaugeOutput(d, "Image Registration", "Registering image ...")
263 023e1217 Nikos Skalkotos
    try:
264 f5174d2c Nikos Skalkotos
        out = session['image'].out
265 023e1217 Nikos Skalkotos
        out.add(gauge)
266 023e1217 Nikos Skalkotos
        try:
267 023e1217 Nikos Skalkotos
            try:
268 34e7a04a Nikos Skalkotos
                out.output("Registering %s image with the cloud ..." %
269 34e7a04a Nikos Skalkotos
                           img_type)
270 31160dc8 Nikos Skalkotos
                kamaki = Kamaki(session['account'], out)
271 8e58e699 Nikos Skalkotos
                result = kamaki.register(name, session['pithos_uri'], metadata,
272 8e58e699 Nikos Skalkotos
                                         is_public)
273 023e1217 Nikos Skalkotos
                out.success('done')
274 03eb7dc8 Nikos Skalkotos
                # Upload metadata file
275 34e7a04a Nikos Skalkotos
                out.output("Uploading metadata file ...")
276 8e58e699 Nikos Skalkotos
                metastring = unicode(json.dumps(result, ensure_ascii=False))
277 03eb7dc8 Nikos Skalkotos
                kamaki.upload(StringIO.StringIO(metastring),
278 03eb7dc8 Nikos Skalkotos
                              size=len(metastring),
279 03eb7dc8 Nikos Skalkotos
                              remote_path="%s.meta" % session['upload'])
280 03eb7dc8 Nikos Skalkotos
                out.success("done")
281 3afe6b44 Nikos Skalkotos
                if is_public:
282 34e7a04a Nikos Skalkotos
                    out.output("Sharing metadata and md5sum files ...")
283 3afe6b44 Nikos Skalkotos
                    kamaki.share("%s.meta" % session['upload'])
284 3afe6b44 Nikos Skalkotos
                    kamaki.share("%s.md5sum" % session['upload'])
285 3afe6b44 Nikos Skalkotos
                    out.success('done')
286 023e1217 Nikos Skalkotos
            except ClientError as e:
287 ffc64d7c Nikos Skalkotos
                d.msgbox("Error in storage service client: %s" % e.message)
288 023e1217 Nikos Skalkotos
                return False
289 023e1217 Nikos Skalkotos
        finally:
290 023e1217 Nikos Skalkotos
            out.remove(gauge)
291 023e1217 Nikos Skalkotos
    finally:
292 023e1217 Nikos Skalkotos
        gauge.cleanup()
293 023e1217 Nikos Skalkotos
294 ffc64d7c Nikos Skalkotos
    d.msgbox("%s image `%s' was successfully registered with the cloud as `%s'"
295 37d581b8 Nikos Skalkotos
             % (img_type.title(), session['upload'], name), width=SMALL_WIDTH)
296 023e1217 Nikos Skalkotos
    return True
297 023e1217 Nikos Skalkotos
298 023e1217 Nikos Skalkotos
299 49c07ce3 Nikos Skalkotos
def modify_clouds(session):
300 49c07ce3 Nikos Skalkotos
    """Modify existing cloud accounts"""
301 49c07ce3 Nikos Skalkotos
    d = session['dialog']
302 49c07ce3 Nikos Skalkotos
303 49c07ce3 Nikos Skalkotos
    while 1:
304 49c07ce3 Nikos Skalkotos
        clouds = Kamaki.get_clouds()
305 49c07ce3 Nikos Skalkotos
        if not len(clouds):
306 49c07ce3 Nikos Skalkotos
            if not add_cloud(session):
307 49c07ce3 Nikos Skalkotos
                break
308 49c07ce3 Nikos Skalkotos
            continue
309 49c07ce3 Nikos Skalkotos
310 49c07ce3 Nikos Skalkotos
        choices = []
311 49c07ce3 Nikos Skalkotos
        for (name, cloud) in clouds.items():
312 49c07ce3 Nikos Skalkotos
            descr = cloud['description'] if 'description' in cloud else ''
313 49c07ce3 Nikos Skalkotos
            choices.append((name, descr))
314 49c07ce3 Nikos Skalkotos
315 49c07ce3 Nikos Skalkotos
        (code, choice) = d.menu(
316 49c07ce3 Nikos Skalkotos
            "In this menu you can edit existing cloud accounts or add new "
317 49c07ce3 Nikos Skalkotos
            " ones. Press <Edit> to edit an existing account or <Add> to add "
318 49c07ce3 Nikos Skalkotos
            " a new one. Press <Back> or hit <ESC> when done.", height=18,
319 49c07ce3 Nikos Skalkotos
            width=WIDTH, choices=choices, menu_height=10, ok_label="Edit",
320 49c07ce3 Nikos Skalkotos
            extra_button=1, extra_label="Add", cancel="Back", help_button=1,
321 49c07ce3 Nikos Skalkotos
            title="Clouds")
322 49c07ce3 Nikos Skalkotos
323 49c07ce3 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
324 49c07ce3 Nikos Skalkotos
            return True
325 49c07ce3 Nikos Skalkotos
        elif code == d.DIALOG_OK:  # Edit button
326 49c07ce3 Nikos Skalkotos
            edit_cloud(session, choice)
327 49c07ce3 Nikos Skalkotos
        elif code == d.DIALOG_EXTRA:  # Add button
328 49c07ce3 Nikos Skalkotos
            add_cloud(session)
329 49c07ce3 Nikos Skalkotos
330 49c07ce3 Nikos Skalkotos
331 49c07ce3 Nikos Skalkotos
def delete_clouds(session):
332 49c07ce3 Nikos Skalkotos
    """Delete existing cloud accounts"""
333 49c07ce3 Nikos Skalkotos
    d = session['dialog']
334 49c07ce3 Nikos Skalkotos
335 49c07ce3 Nikos Skalkotos
    choices = []
336 49c07ce3 Nikos Skalkotos
    for (name, cloud) in Kamaki.get_clouds().items():
337 49c07ce3 Nikos Skalkotos
        descr = cloud['description'] if 'description' in cloud else ''
338 49c07ce3 Nikos Skalkotos
        choices.append((name, descr, 0))
339 49c07ce3 Nikos Skalkotos
340 49c07ce3 Nikos Skalkotos
    if len(choices) == 0:
341 49c07ce3 Nikos Skalkotos
        d.msgbox("No available clouds to delete!", width=SMALL_WIDTH)
342 49c07ce3 Nikos Skalkotos
        return True
343 49c07ce3 Nikos Skalkotos
344 49c07ce3 Nikos Skalkotos
    (code, to_delete) = d.checklist("Choose which cloud accounts to delete:",
345 49c07ce3 Nikos Skalkotos
                                    choices=choices, width=WIDTH)
346 5e18a927 Nikos Skalkotos
    to_delete = map(lambda x: x.strip('"'), to_delete)  # Needed for OpenSUSE
347 49c07ce3 Nikos Skalkotos
348 49c07ce3 Nikos Skalkotos
    if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
349 49c07ce3 Nikos Skalkotos
        return False
350 49c07ce3 Nikos Skalkotos
351 49c07ce3 Nikos Skalkotos
    if not len(to_delete):
352 49c07ce3 Nikos Skalkotos
        d.msgbox("Nothing selected!", width=SMALL_WIDTH)
353 49c07ce3 Nikos Skalkotos
        return False
354 49c07ce3 Nikos Skalkotos
355 49c07ce3 Nikos Skalkotos
    if not d.yesno("Are you sure you want to remove the selected cloud "
356 49c07ce3 Nikos Skalkotos
                   "accounts?", width=WIDTH, defaultno=1):
357 49c07ce3 Nikos Skalkotos
        for i in to_delete:
358 49c07ce3 Nikos Skalkotos
            Kamaki.remove_cloud(i)
359 49c07ce3 Nikos Skalkotos
            if 'cloud' in session and session['cloud'] == i:
360 49c07ce3 Nikos Skalkotos
                del session['cloud']
361 49c07ce3 Nikos Skalkotos
                if 'account' in session:
362 49c07ce3 Nikos Skalkotos
                    del session['account']
363 49c07ce3 Nikos Skalkotos
    else:
364 49c07ce3 Nikos Skalkotos
        return False
365 49c07ce3 Nikos Skalkotos
366 49c07ce3 Nikos Skalkotos
    d.msgbox("%d cloud accounts were deleted." % len(to_delete),
367 49c07ce3 Nikos Skalkotos
             width=SMALL_WIDTH)
368 49c07ce3 Nikos Skalkotos
    return True
369 49c07ce3 Nikos Skalkotos
370 49c07ce3 Nikos Skalkotos
371 023e1217 Nikos Skalkotos
def kamaki_menu(session):
372 88f83027 Nikos Skalkotos
    """Show kamaki related actions"""
373 023e1217 Nikos Skalkotos
    d = session['dialog']
374 49c07ce3 Nikos Skalkotos
    default_item = "Cloud"
375 023e1217 Nikos Skalkotos
376 49c07ce3 Nikos Skalkotos
    if 'cloud' not in session:
377 49c07ce3 Nikos Skalkotos
        cloud = Kamaki.get_default_cloud_name()
378 49c07ce3 Nikos Skalkotos
        if cloud:
379 49c07ce3 Nikos Skalkotos
            session['cloud'] = cloud
380 49c07ce3 Nikos Skalkotos
            session['account'] = Kamaki.get_account(cloud)
381 31160dc8 Nikos Skalkotos
            if not session['account']:
382 31160dc8 Nikos Skalkotos
                del session['account']
383 49c07ce3 Nikos Skalkotos
        else:
384 49c07ce3 Nikos Skalkotos
            default_item = "Add/Edit"
385 023e1217 Nikos Skalkotos
386 023e1217 Nikos Skalkotos
    while 1:
387 49c07ce3 Nikos Skalkotos
        cloud = session["cloud"] if "cloud" in session else "<none>"
388 49c07ce3 Nikos Skalkotos
        if 'account' not in session and 'cloud' in session:
389 49c07ce3 Nikos Skalkotos
            cloud += " <invalid>"
390 49c07ce3 Nikos Skalkotos
391 023e1217 Nikos Skalkotos
        upload = session["upload"] if "upload" in session else "<none>"
392 023e1217 Nikos Skalkotos
393 49c07ce3 Nikos Skalkotos
        choices = [("Add/Edit", "Add/Edit cloud accounts"),
394 49c07ce3 Nikos Skalkotos
                   ("Delete", "Delete existing cloud accounts"),
395 49c07ce3 Nikos Skalkotos
                   ("Cloud", "Select cloud account to use: %s" % cloud),
396 ffc64d7c Nikos Skalkotos
                   ("Upload", "Upload image to the cloud"),
397 ffc64d7c Nikos Skalkotos
                   ("Register", "Register image with the cloud: %s" % upload)]
398 023e1217 Nikos Skalkotos
399 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
400 023e1217 Nikos Skalkotos
            text="Choose one of the following or press <Back> to go back.",
401 023e1217 Nikos Skalkotos
            width=WIDTH, choices=choices, cancel="Back", height=13,
402 023e1217 Nikos Skalkotos
            menu_height=5, default_item=default_item,
403 023e1217 Nikos Skalkotos
            title="Image Registration Menu")
404 023e1217 Nikos Skalkotos
405 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
406 023e1217 Nikos Skalkotos
            return False
407 023e1217 Nikos Skalkotos
408 49c07ce3 Nikos Skalkotos
        if choice == "Add/Edit":
409 49c07ce3 Nikos Skalkotos
            if modify_clouds(session):
410 49c07ce3 Nikos Skalkotos
                default_item = "Cloud"
411 49c07ce3 Nikos Skalkotos
        elif choice == "Delete":
412 49c07ce3 Nikos Skalkotos
            if delete_clouds(session):
413 49c07ce3 Nikos Skalkotos
                if len(Kamaki.get_clouds()):
414 49c07ce3 Nikos Skalkotos
                    default_item = "Cloud"
415 49c07ce3 Nikos Skalkotos
                else:
416 47505e53 Nikos Skalkotos
                    default_item = "Add/Edit"
417 49c07ce3 Nikos Skalkotos
            else:
418 47505e53 Nikos Skalkotos
                default_item = "Delete"
419 49c07ce3 Nikos Skalkotos
        elif choice == "Cloud":
420 49c07ce3 Nikos Skalkotos
            default_item = "Cloud"
421 49c07ce3 Nikos Skalkotos
            clouds = Kamaki.get_clouds()
422 49c07ce3 Nikos Skalkotos
            if not len(clouds):
423 49c07ce3 Nikos Skalkotos
                d.msgbox("No clouds available. Please add a new cloud!",
424 49c07ce3 Nikos Skalkotos
                         width=SMALL_WIDTH)
425 49c07ce3 Nikos Skalkotos
                default_item = "Add/Edit"
426 49c07ce3 Nikos Skalkotos
                continue
427 49c07ce3 Nikos Skalkotos
428 49c07ce3 Nikos Skalkotos
            if 'cloud' not in session:
429 49c07ce3 Nikos Skalkotos
                session['cloud'] = clouds.keys()[0]
430 49c07ce3 Nikos Skalkotos
431 49c07ce3 Nikos Skalkotos
            choices = []
432 49c07ce3 Nikos Skalkotos
            for name, info in clouds.items():
433 49c07ce3 Nikos Skalkotos
                default = 1 if session['cloud'] == name else 0
434 49c07ce3 Nikos Skalkotos
                descr = info['description'] if 'description' in info else ""
435 49c07ce3 Nikos Skalkotos
                choices.append((name, descr, default))
436 49c07ce3 Nikos Skalkotos
437 49c07ce3 Nikos Skalkotos
            (code, answer) = d.radiolist("Please select a cloud:",
438 49c07ce3 Nikos Skalkotos
                                         width=WIDTH, choices=choices)
439 023e1217 Nikos Skalkotos
            if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
440 023e1217 Nikos Skalkotos
                continue
441 023e1217 Nikos Skalkotos
            else:
442 49c07ce3 Nikos Skalkotos
                session['account'] = Kamaki.get_account(answer)
443 49c07ce3 Nikos Skalkotos
444 49c07ce3 Nikos Skalkotos
                if session['account'] is None:  # invalid account
445 49c07ce3 Nikos Skalkotos
                    if not d.yesno("The cloud %s' is not valid! Would you "
446 49c07ce3 Nikos Skalkotos
                                   "like to edit it?" % answer, width=WIDTH):
447 49c07ce3 Nikos Skalkotos
                        if edit_cloud(session, answer):
448 49c07ce3 Nikos Skalkotos
                            session['account'] = Kamaki.get_account(answer)
449 49c07ce3 Nikos Skalkotos
                            Kamaki.set_default_cloud(answer)
450 49c07ce3 Nikos Skalkotos
451 31160dc8 Nikos Skalkotos
                if session['account'] is not None:
452 49c07ce3 Nikos Skalkotos
                    session['cloud'] = answer
453 49c07ce3 Nikos Skalkotos
                    Kamaki.set_default_cloud(answer)
454 31160dc8 Nikos Skalkotos
                    default_item = "Upload"
455 31160dc8 Nikos Skalkotos
                else:
456 31160dc8 Nikos Skalkotos
                    del session['account']
457 49c07ce3 Nikos Skalkotos
                    del session['cloud']
458 023e1217 Nikos Skalkotos
        elif choice == "Upload":
459 023e1217 Nikos Skalkotos
            if upload_image(session):
460 023e1217 Nikos Skalkotos
                default_item = "Register"
461 023e1217 Nikos Skalkotos
            else:
462 023e1217 Nikos Skalkotos
                default_item = "Upload"
463 023e1217 Nikos Skalkotos
        elif choice == "Register":
464 023e1217 Nikos Skalkotos
            if register_image(session):
465 023e1217 Nikos Skalkotos
                return True
466 023e1217 Nikos Skalkotos
            else:
467 023e1217 Nikos Skalkotos
                default_item = "Register"
468 023e1217 Nikos Skalkotos
469 023e1217 Nikos Skalkotos
470 023e1217 Nikos Skalkotos
def add_property(session):
471 88f83027 Nikos Skalkotos
    """Add a new property to the image"""
472 023e1217 Nikos Skalkotos
    d = session['dialog']
473 023e1217 Nikos Skalkotos
474 023e1217 Nikos Skalkotos
    while 1:
475 023e1217 Nikos Skalkotos
        (code, answer) = d.inputbox("Please provide a name for a new image"
476 023e1217 Nikos Skalkotos
                                    " property:", width=WIDTH)
477 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
478 023e1217 Nikos Skalkotos
            return False
479 023e1217 Nikos Skalkotos
480 023e1217 Nikos Skalkotos
        name = answer.strip()
481 023e1217 Nikos Skalkotos
        if len(name) == 0:
482 023e1217 Nikos Skalkotos
            d.msgbox("A property name cannot be empty", width=SMALL_WIDTH)
483 023e1217 Nikos Skalkotos
            continue
484 023e1217 Nikos Skalkotos
485 023e1217 Nikos Skalkotos
        break
486 023e1217 Nikos Skalkotos
487 023e1217 Nikos Skalkotos
    while 1:
488 023e1217 Nikos Skalkotos
        (code, answer) = d.inputbox("Please provide a value for image "
489 023e1217 Nikos Skalkotos
                                    "property %s" % name, width=WIDTH)
490 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
491 023e1217 Nikos Skalkotos
            return False
492 023e1217 Nikos Skalkotos
493 023e1217 Nikos Skalkotos
        value = answer.strip()
494 023e1217 Nikos Skalkotos
        if len(value) == 0:
495 023e1217 Nikos Skalkotos
            d.msgbox("Value cannot be empty", width=SMALL_WIDTH)
496 023e1217 Nikos Skalkotos
            continue
497 023e1217 Nikos Skalkotos
498 023e1217 Nikos Skalkotos
        break
499 023e1217 Nikos Skalkotos
500 023e1217 Nikos Skalkotos
    session['metadata'][name] = value
501 023e1217 Nikos Skalkotos
502 023e1217 Nikos Skalkotos
    return True
503 023e1217 Nikos Skalkotos
504 023e1217 Nikos Skalkotos
505 6ca82c22 Nikos Skalkotos
def show_properties_help(session):
506 6ca82c22 Nikos Skalkotos
    """Show help for image properties"""
507 6ca82c22 Nikos Skalkotos
    d = session['dialog']
508 6ca82c22 Nikos Skalkotos
509 6ca82c22 Nikos Skalkotos
    help_file = get_help_file("image_properties")
510 6ca82c22 Nikos Skalkotos
    assert os.path.exists(help_file)
511 6ca82c22 Nikos Skalkotos
    d.textbox(help_file, title="Image Properties", width=70, height=40)
512 6ca82c22 Nikos Skalkotos
513 6ca82c22 Nikos Skalkotos
514 023e1217 Nikos Skalkotos
def modify_properties(session):
515 88f83027 Nikos Skalkotos
    """Modify an existing image property"""
516 023e1217 Nikos Skalkotos
    d = session['dialog']
517 023e1217 Nikos Skalkotos
518 023e1217 Nikos Skalkotos
    while 1:
519 023e1217 Nikos Skalkotos
        choices = []
520 023e1217 Nikos Skalkotos
        for (key, val) in session['metadata'].items():
521 023e1217 Nikos Skalkotos
            choices.append((str(key), str(val)))
522 023e1217 Nikos Skalkotos
523 6ca82c22 Nikos Skalkotos
        if len(choices) == 0:
524 6ca82c22 Nikos Skalkotos
            code = d.yesno(
525 6ca82c22 Nikos Skalkotos
                "No image properties are available. "
526 6ca82c22 Nikos Skalkotos
                "Would you like to add a new one?", width=WIDTH, help_button=1)
527 6ca82c22 Nikos Skalkotos
            if code == d.DIALOG_OK:
528 6ca82c22 Nikos Skalkotos
                if not add_property(session):
529 6ca82c22 Nikos Skalkotos
                    return True
530 6ca82c22 Nikos Skalkotos
            elif code == d.DIALOG_CANCEL:
531 6ca82c22 Nikos Skalkotos
                return True
532 6ca82c22 Nikos Skalkotos
            elif code == d.DIALOG_HELP:
533 6ca82c22 Nikos Skalkotos
                show_properties_help(session)
534 6ca82c22 Nikos Skalkotos
            continue
535 6ca82c22 Nikos Skalkotos
536 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
537 023e1217 Nikos Skalkotos
            "In this menu you can edit existing image properties or add new "
538 023e1217 Nikos Skalkotos
            "ones. Be careful! Most properties have special meaning and "
539 023e1217 Nikos Skalkotos
            "alter the image deployment behaviour. Press <HELP> to see more "
540 023e1217 Nikos Skalkotos
            "information about image properties. Press <BACK> when done.",
541 023e1217 Nikos Skalkotos
            height=18, width=WIDTH, choices=choices, menu_height=10,
542 023e1217 Nikos Skalkotos
            ok_label="Edit", extra_button=1, extra_label="Add", cancel="Back",
543 023e1217 Nikos Skalkotos
            help_button=1, title="Image Properties")
544 023e1217 Nikos Skalkotos
545 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
546 023e1217 Nikos Skalkotos
            return True
547 023e1217 Nikos Skalkotos
        # Edit button
548 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_OK:
549 023e1217 Nikos Skalkotos
            (code, answer) = d.inputbox("Please provide a new value for the "
550 023e1217 Nikos Skalkotos
                                        "image property with name `%s':" %
551 023e1217 Nikos Skalkotos
                                        choice,
552 023e1217 Nikos Skalkotos
                                        init=session['metadata'][choice],
553 023e1217 Nikos Skalkotos
                                        width=WIDTH)
554 023e1217 Nikos Skalkotos
            if code not in (d.DIALOG_CANCEL, d.DIALOG_ESC):
555 023e1217 Nikos Skalkotos
                value = answer.strip()
556 023e1217 Nikos Skalkotos
                if len(value) == 0:
557 023e1217 Nikos Skalkotos
                    d.msgbox("Value cannot be empty!")
558 023e1217 Nikos Skalkotos
                    continue
559 023e1217 Nikos Skalkotos
                else:
560 023e1217 Nikos Skalkotos
                    session['metadata'][choice] = value
561 023e1217 Nikos Skalkotos
        # ADD button
562 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_EXTRA:
563 023e1217 Nikos Skalkotos
            add_property(session)
564 023e1217 Nikos Skalkotos
        elif code == 'help':
565 6ca82c22 Nikos Skalkotos
            show_properties_help(session)
566 023e1217 Nikos Skalkotos
567 023e1217 Nikos Skalkotos
568 023e1217 Nikos Skalkotos
def delete_properties(session):
569 88f83027 Nikos Skalkotos
    """Delete an image property"""
570 023e1217 Nikos Skalkotos
    d = session['dialog']
571 023e1217 Nikos Skalkotos
572 023e1217 Nikos Skalkotos
    choices = []
573 023e1217 Nikos Skalkotos
    for (key, val) in session['metadata'].items():
574 023e1217 Nikos Skalkotos
        choices.append((key, "%s" % val, 0))
575 023e1217 Nikos Skalkotos
576 6ca82c22 Nikos Skalkotos
    if len(choices) == 0:
577 6ca82c22 Nikos Skalkotos
        d.msgbox("No available images properties to delete!",
578 6ca82c22 Nikos Skalkotos
                 width=SMALL_WIDTH)
579 6ca82c22 Nikos Skalkotos
        return True
580 6ca82c22 Nikos Skalkotos
581 023e1217 Nikos Skalkotos
    (code, to_delete) = d.checklist("Choose which properties to delete:",
582 023e1217 Nikos Skalkotos
                                    choices=choices, width=WIDTH)
583 5e18a927 Nikos Skalkotos
    to_delete = map(lambda x: x.strip('"'), to_delete)  # needed for OpenSUSE
584 023e1217 Nikos Skalkotos
585 023e1217 Nikos Skalkotos
    # If the user exits with ESC or CANCEL, the returned tag list is empty.
586 023e1217 Nikos Skalkotos
    for i in to_delete:
587 023e1217 Nikos Skalkotos
        del session['metadata'][i]
588 023e1217 Nikos Skalkotos
589 023e1217 Nikos Skalkotos
    cnt = len(to_delete)
590 023e1217 Nikos Skalkotos
    if cnt > 0:
591 023e1217 Nikos Skalkotos
        d.msgbox("%d image properties were deleted." % cnt, width=SMALL_WIDTH)
592 023e1217 Nikos Skalkotos
        return True
593 023e1217 Nikos Skalkotos
    else:
594 023e1217 Nikos Skalkotos
        return False
595 023e1217 Nikos Skalkotos
596 023e1217 Nikos Skalkotos
597 023e1217 Nikos Skalkotos
def exclude_tasks(session):
598 88f83027 Nikos Skalkotos
    """Exclude specific tasks from running during image deployment"""
599 023e1217 Nikos Skalkotos
    d = session['dialog']
600 e482b7f9 Nikos Skalkotos
    image = session['image']
601 e482b7f9 Nikos Skalkotos
602 d0daafa2 Nikos Skalkotos
    if image.is_unsupported():
603 d0daafa2 Nikos Skalkotos
        d.msgbox("Image deployment configuration is disabled for unsupported "
604 d0daafa2 Nikos Skalkotos
                 "images.", width=SMALL_WIDTH)
605 e482b7f9 Nikos Skalkotos
        return False
606 023e1217 Nikos Skalkotos
607 023e1217 Nikos Skalkotos
    index = 0
608 023e1217 Nikos Skalkotos
    displayed_index = 1
609 023e1217 Nikos Skalkotos
    choices = []
610 023e1217 Nikos Skalkotos
    mapping = {}
611 023e1217 Nikos Skalkotos
    if 'excluded_tasks' not in session:
612 023e1217 Nikos Skalkotos
        session['excluded_tasks'] = []
613 023e1217 Nikos Skalkotos
614 023e1217 Nikos Skalkotos
    if -1 in session['excluded_tasks']:
615 023e1217 Nikos Skalkotos
        if not d.yesno("Image deployment configuration is disabled. "
616 023e1217 Nikos Skalkotos
                       "Do you wish to enable it?", width=SMALL_WIDTH):
617 023e1217 Nikos Skalkotos
            session['excluded_tasks'].remove(-1)
618 023e1217 Nikos Skalkotos
        else:
619 023e1217 Nikos Skalkotos
            return False
620 023e1217 Nikos Skalkotos
621 023e1217 Nikos Skalkotos
    for (msg, task, osfamily) in CONFIGURATION_TASKS:
622 023e1217 Nikos Skalkotos
        if session['metadata']['OSFAMILY'] in osfamily:
623 023e1217 Nikos Skalkotos
            checked = 1 if index in session['excluded_tasks'] else 0
624 023e1217 Nikos Skalkotos
            choices.append((str(displayed_index), msg, checked))
625 023e1217 Nikos Skalkotos
            mapping[displayed_index] = index
626 023e1217 Nikos Skalkotos
            displayed_index += 1
627 023e1217 Nikos Skalkotos
        index += 1
628 023e1217 Nikos Skalkotos
629 023e1217 Nikos Skalkotos
    while 1:
630 023e1217 Nikos Skalkotos
        (code, tags) = d.checklist(
631 023e1217 Nikos Skalkotos
            text="Please choose which configuration tasks you would like to "
632 023e1217 Nikos Skalkotos
                 "prevent from running during image deployment. "
633 023e1217 Nikos Skalkotos
                 "Press <No Config> to supress any configuration. "
634 023e1217 Nikos Skalkotos
                 "Press <Help> for more help on the image deployment "
635 023e1217 Nikos Skalkotos
                 "configuration tasks.",
636 023e1217 Nikos Skalkotos
            choices=choices, height=19, list_height=8, width=WIDTH,
637 023e1217 Nikos Skalkotos
            help_button=1, extra_button=1, extra_label="No Config",
638 023e1217 Nikos Skalkotos
            title="Exclude Configuration Tasks")
639 5e18a927 Nikos Skalkotos
        tags = map(lambda x: x.strip('"'), tags)  # Needed for OpenSUSE
640 023e1217 Nikos Skalkotos
641 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
642 023e1217 Nikos Skalkotos
            return False
643 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_HELP:
644 023e1217 Nikos Skalkotos
            help_file = get_help_file("configuration_tasks")
645 023e1217 Nikos Skalkotos
            assert os.path.exists(help_file)
646 023e1217 Nikos Skalkotos
            d.textbox(help_file, title="Configuration Tasks",
647 023e1217 Nikos Skalkotos
                      width=70, height=40)
648 023e1217 Nikos Skalkotos
        # No Config button
649 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_EXTRA:
650 023e1217 Nikos Skalkotos
            session['excluded_tasks'] = [-1]
651 023e1217 Nikos Skalkotos
            session['task_metadata'] = ["EXCLUDE_ALL_TASKS"]
652 023e1217 Nikos Skalkotos
            break
653 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_OK:
654 023e1217 Nikos Skalkotos
            session['excluded_tasks'] = []
655 023e1217 Nikos Skalkotos
            for tag in tags:
656 023e1217 Nikos Skalkotos
                session['excluded_tasks'].append(mapping[int(tag)])
657 023e1217 Nikos Skalkotos
658 023e1217 Nikos Skalkotos
            exclude_metadata = []
659 023e1217 Nikos Skalkotos
            for task in session['excluded_tasks']:
660 023e1217 Nikos Skalkotos
                exclude_metadata.extend(CONFIGURATION_TASKS[task][1])
661 023e1217 Nikos Skalkotos
662 023e1217 Nikos Skalkotos
            session['task_metadata'] = map(lambda x: "EXCLUDE_TASK_%s" % x,
663 023e1217 Nikos Skalkotos
                                           exclude_metadata)
664 023e1217 Nikos Skalkotos
            break
665 023e1217 Nikos Skalkotos
666 023e1217 Nikos Skalkotos
    return True
667 023e1217 Nikos Skalkotos
668 023e1217 Nikos Skalkotos
669 0eac0256 Nikos Skalkotos
def sysprep_params(session):
670 47505e53 Nikos Skalkotos
    """Collect the needed sysprep parameters"""
671 0eac0256 Nikos Skalkotos
    d = session['dialog']
672 0eac0256 Nikos Skalkotos
    image = session['image']
673 0eac0256 Nikos Skalkotos
674 0eac0256 Nikos Skalkotos
    available = image.os.sysprep_params
675 f59ad913 Nikos Skalkotos
    needed = image.os.needed_sysprep_params
676 0eac0256 Nikos Skalkotos
677 0eac0256 Nikos Skalkotos
    if len(needed) == 0:
678 0eac0256 Nikos Skalkotos
        return True
679 0eac0256 Nikos Skalkotos
680 f584265d Nikos Skalkotos
    def print_form(names, extra_button=False):
681 f584265d Nikos Skalkotos
        """print the dialog form providing sysprep_params"""
682 82e8c357 Nikos Skalkotos
        fields = []
683 82e8c357 Nikos Skalkotos
        for name in names:
684 82e8c357 Nikos Skalkotos
            param = needed[name]
685 82e8c357 Nikos Skalkotos
            default = str(available[name]) if name in available else ""
686 82e8c357 Nikos Skalkotos
            fields.append(("%s: " % param.description, default,
687 82e8c357 Nikos Skalkotos
                           SYSPREP_PARAM_MAXLEN))
688 0eac0256 Nikos Skalkotos
689 f584265d Nikos Skalkotos
        kwargs = {}
690 f584265d Nikos Skalkotos
        if extra_button:
691 f584265d Nikos Skalkotos
            kwargs['extra_button'] = 1
692 f584265d Nikos Skalkotos
            kwargs['extra_label'] = "Advanced"
693 f584265d Nikos Skalkotos
694 82e8c357 Nikos Skalkotos
        txt = "Please provide the following system preparation parameters:"
695 f584265d Nikos Skalkotos
        return d.form(txt, height=13, width=WIDTH, form_height=len(fields),
696 f584265d Nikos Skalkotos
                      fields=fields, **kwargs)
697 0eac0256 Nikos Skalkotos
698 f584265d Nikos Skalkotos
    def check_params(names, values):
699 f584265d Nikos Skalkotos
        """check if the provided sysprep parameters have leagal values"""
700 f584265d Nikos Skalkotos
        for i in range(len(names)):
701 f584265d Nikos Skalkotos
            param = needed[names[i]]
702 f584265d Nikos Skalkotos
            try:
703 f584265d Nikos Skalkotos
                normalized = param.type(values[i])
704 f584265d Nikos Skalkotos
                if param.validate(normalized):
705 f584265d Nikos Skalkotos
                    image.os.sysprep_params[names[i]] = normalized
706 f584265d Nikos Skalkotos
                    continue
707 f584265d Nikos Skalkotos
            except ValueError:
708 f584265d Nikos Skalkotos
                pass
709 f584265d Nikos Skalkotos
710 f584265d Nikos Skalkotos
            d.msgbox("Invalid value for parameter: `%s'" % names[i],
711 f584265d Nikos Skalkotos
                     width=SMALL_WIDTH)
712 82e8c357 Nikos Skalkotos
            return False
713 f584265d Nikos Skalkotos
        return True
714 0eac0256 Nikos Skalkotos
715 f584265d Nikos Skalkotos
    simple_names = [k for k, v in needed.items() if v.default is None]
716 f584265d Nikos Skalkotos
    advanced_names = [k for k, v in needed.items() if v.default is not None]
717 f584265d Nikos Skalkotos
718 f584265d Nikos Skalkotos
    while 1:
719 f584265d Nikos Skalkotos
        code, output = print_form(simple_names, extra_button=True)
720 f584265d Nikos Skalkotos
721 f584265d Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
722 f584265d Nikos Skalkotos
            return False
723 f584265d Nikos Skalkotos
        if code == d.DIALOG_EXTRA:
724 f584265d Nikos Skalkotos
            while 1:
725 f584265d Nikos Skalkotos
                code, output = print_form(advanced_names)
726 f584265d Nikos Skalkotos
                if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
727 f584265d Nikos Skalkotos
                    break
728 f584265d Nikos Skalkotos
                if check_params(advanced_names, output):
729 f584265d Nikos Skalkotos
                    break
730 f584265d Nikos Skalkotos
            continue
731 678b382b Nikos Skalkotos
732 f584265d Nikos Skalkotos
        if check_params(simple_names, output):
733 82e8c357 Nikos Skalkotos
            break
734 0eac0256 Nikos Skalkotos
735 0eac0256 Nikos Skalkotos
    return True
736 0eac0256 Nikos Skalkotos
737 0eac0256 Nikos Skalkotos
738 023e1217 Nikos Skalkotos
def sysprep(session):
739 88f83027 Nikos Skalkotos
    """Perform various system preperation tasks on the image"""
740 023e1217 Nikos Skalkotos
    d = session['dialog']
741 f5174d2c Nikos Skalkotos
    image = session['image']
742 023e1217 Nikos Skalkotos
743 023e1217 Nikos Skalkotos
    # Is the image already shrinked?
744 023e1217 Nikos Skalkotos
    if 'shrinked' in session and session['shrinked']:
745 023e1217 Nikos Skalkotos
        msg = "It seems you have shrinked the image. Running system " \
746 023e1217 Nikos Skalkotos
              "preparation tasks on a shrinked image is dangerous."
747 023e1217 Nikos Skalkotos
748 023e1217 Nikos Skalkotos
        if d.yesno("%s\n\nDo you really want to continue?" % msg,
749 023e1217 Nikos Skalkotos
                   width=SMALL_WIDTH, defaultno=1):
750 023e1217 Nikos Skalkotos
            return
751 023e1217 Nikos Skalkotos
752 023e1217 Nikos Skalkotos
    wrapper = textwrap.TextWrapper(width=WIDTH - 5)
753 023e1217 Nikos Skalkotos
754 fa65eda1 Nikos Skalkotos
    syspreps = image.os.list_syspreps()
755 023e1217 Nikos Skalkotos
756 023e1217 Nikos Skalkotos
    if len(syspreps) == 0:
757 023e1217 Nikos Skalkotos
        d.msgbox("No system preparation task available to run!",
758 023e1217 Nikos Skalkotos
                 title="System Preperation", width=SMALL_WIDTH)
759 023e1217 Nikos Skalkotos
        return
760 023e1217 Nikos Skalkotos
761 023e1217 Nikos Skalkotos
    while 1:
762 023e1217 Nikos Skalkotos
        choices = []
763 023e1217 Nikos Skalkotos
        index = 0
764 497fadb3 Nikos Skalkotos
765 497fadb3 Nikos Skalkotos
        help_title = "System Preperation Tasks"
766 497fadb3 Nikos Skalkotos
        sysprep_help = "%s\n%s\n\n" % (help_title, '=' * len(help_title))
767 497fadb3 Nikos Skalkotos
768 023e1217 Nikos Skalkotos
        for sysprep in syspreps:
769 f5174d2c Nikos Skalkotos
            name, descr = image.os.sysprep_info(sysprep)
770 023e1217 Nikos Skalkotos
            display_name = name.replace('-', ' ').capitalize()
771 023e1217 Nikos Skalkotos
            sysprep_help += "%s\n" % display_name
772 023e1217 Nikos Skalkotos
            sysprep_help += "%s\n" % ('-' * len(display_name))
773 023e1217 Nikos Skalkotos
            sysprep_help += "%s\n\n" % wrapper.fill(" ".join(descr.split()))
774 023e1217 Nikos Skalkotos
            enabled = 1 if sysprep.enabled else 0
775 023e1217 Nikos Skalkotos
            choices.append((str(index + 1), display_name, enabled))
776 023e1217 Nikos Skalkotos
            index += 1
777 023e1217 Nikos Skalkotos
778 023e1217 Nikos Skalkotos
        (code, tags) = d.checklist(
779 023e1217 Nikos Skalkotos
            "Please choose which system preparation tasks you would like to "
780 023e1217 Nikos Skalkotos
            "run on the image. Press <Help> to see details about the system "
781 023e1217 Nikos Skalkotos
            "preparation tasks.", title="Run system preparation tasks",
782 023e1217 Nikos Skalkotos
            choices=choices, width=70, ok_label="Run", help_button=1)
783 5e18a927 Nikos Skalkotos
        tags = map(lambda x: x.strip('"'), tags)  # Needed for OpenSUSE
784 023e1217 Nikos Skalkotos
785 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
786 023e1217 Nikos Skalkotos
            return False
787 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_HELP:
788 023e1217 Nikos Skalkotos
            d.scrollbox(sysprep_help, width=WIDTH)
789 023e1217 Nikos Skalkotos
        elif code == d.DIALOG_OK:
790 023e1217 Nikos Skalkotos
            # Enable selected syspreps and disable the rest
791 023e1217 Nikos Skalkotos
            for i in range(len(syspreps)):
792 023e1217 Nikos Skalkotos
                if str(i + 1) in tags:
793 f5174d2c Nikos Skalkotos
                    image.os.enable_sysprep(syspreps[i])
794 023e1217 Nikos Skalkotos
                else:
795 f5174d2c Nikos Skalkotos
                    image.os.disable_sysprep(syspreps[i])
796 023e1217 Nikos Skalkotos
797 fa65eda1 Nikos Skalkotos
            if len([s for s in image.os.list_syspreps() if s.enabled]) == 0:
798 fa65eda1 Nikos Skalkotos
                d.msgbox("No system preperation task is selected!",
799 fa65eda1 Nikos Skalkotos
                         title="System Preperation", width=SMALL_WIDTH)
800 fa65eda1 Nikos Skalkotos
                continue
801 fa65eda1 Nikos Skalkotos
802 0eac0256 Nikos Skalkotos
            if not sysprep_params(session):
803 0eac0256 Nikos Skalkotos
                continue
804 0eac0256 Nikos Skalkotos
805 023e1217 Nikos Skalkotos
            infobox = InfoBoxOutput(d, "Image Configuration")
806 023e1217 Nikos Skalkotos
            try:
807 f5174d2c Nikos Skalkotos
                image.out.add(infobox)
808 023e1217 Nikos Skalkotos
                try:
809 71b0ab28 Nikos Skalkotos
                    # The checksum is invalid. We have mounted the image rw
810 71b0ab28 Nikos Skalkotos
                    if 'checksum' in session:
811 71b0ab28 Nikos Skalkotos
                        del session['checksum']
812 71b0ab28 Nikos Skalkotos
813 71b0ab28 Nikos Skalkotos
                    # Monitor the metadata changes during syspreps
814 71b0ab28 Nikos Skalkotos
                    with MetadataMonitor(session, image.os.meta):
815 71b0ab28 Nikos Skalkotos
                        try:
816 f5174d2c Nikos Skalkotos
                            image.os.do_sysprep()
817 023e1217 Nikos Skalkotos
                            infobox.finalize()
818 71b0ab28 Nikos Skalkotos
                        except FatalError as e:
819 71b0ab28 Nikos Skalkotos
                            title = "System Preparation"
820 71b0ab28 Nikos Skalkotos
                            d.msgbox("System Preparation failed: %s" % e,
821 71b0ab28 Nikos Skalkotos
                                     title=title, width=SMALL_WIDTH)
822 023e1217 Nikos Skalkotos
                finally:
823 f5174d2c Nikos Skalkotos
                    image.out.remove(infobox)
824 023e1217 Nikos Skalkotos
            finally:
825 023e1217 Nikos Skalkotos
                infobox.cleanup()
826 023e1217 Nikos Skalkotos
            break
827 023e1217 Nikos Skalkotos
    return True
828 023e1217 Nikos Skalkotos
829 023e1217 Nikos Skalkotos
830 023e1217 Nikos Skalkotos
def shrink(session):
831 88f83027 Nikos Skalkotos
    """Shrink the image"""
832 023e1217 Nikos Skalkotos
    d = session['dialog']
833 f5174d2c Nikos Skalkotos
    image = session['image']
834 023e1217 Nikos Skalkotos
835 023e1217 Nikos Skalkotos
    shrinked = 'shrinked' in session and session['shrinked']
836 023e1217 Nikos Skalkotos
837 023e1217 Nikos Skalkotos
    if shrinked:
838 023e1217 Nikos Skalkotos
        d.msgbox("The image is already shrinked!", title="Image Shrinking",
839 023e1217 Nikos Skalkotos
                 width=SMALL_WIDTH)
840 023e1217 Nikos Skalkotos
        return True
841 023e1217 Nikos Skalkotos
842 023e1217 Nikos Skalkotos
    msg = "This operation will shrink the last partition of the image to " \
843 023e1217 Nikos Skalkotos
          "reduce the total image size. If the last partition is a swap " \
844 023e1217 Nikos Skalkotos
          "partition, then this partition is removed and the partition " \
845 023e1217 Nikos Skalkotos
          "before that is shrinked. The removed swap partition will be " \
846 023e1217 Nikos Skalkotos
          "recreated during image deployment."
847 023e1217 Nikos Skalkotos
848 023e1217 Nikos Skalkotos
    if not d.yesno("%s\n\nDo you want to continue?" % msg, width=WIDTH,
849 023e1217 Nikos Skalkotos
                   height=12, title="Image Shrinking"):
850 f5174d2c Nikos Skalkotos
        with MetadataMonitor(session, image.meta):
851 023e1217 Nikos Skalkotos
            infobox = InfoBoxOutput(d, "Image Shrinking", height=4)
852 f5174d2c Nikos Skalkotos
            image.out.add(infobox)
853 023e1217 Nikos Skalkotos
            try:
854 f5174d2c Nikos Skalkotos
                image.shrink()
855 023e1217 Nikos Skalkotos
                infobox.finalize()
856 023e1217 Nikos Skalkotos
            finally:
857 f5174d2c Nikos Skalkotos
                image.out.remove(infobox)
858 023e1217 Nikos Skalkotos
859 023e1217 Nikos Skalkotos
        session['shrinked'] = True
860 023e1217 Nikos Skalkotos
        update_background_title(session)
861 023e1217 Nikos Skalkotos
    else:
862 023e1217 Nikos Skalkotos
        return False
863 023e1217 Nikos Skalkotos
864 023e1217 Nikos Skalkotos
    return True
865 023e1217 Nikos Skalkotos
866 023e1217 Nikos Skalkotos
867 023e1217 Nikos Skalkotos
def customization_menu(session):
868 88f83027 Nikos Skalkotos
    """Show image customization menu"""
869 023e1217 Nikos Skalkotos
    d = session['dialog']
870 023e1217 Nikos Skalkotos
871 023e1217 Nikos Skalkotos
    choices = [("Sysprep", "Run various image preparation tasks"),
872 023e1217 Nikos Skalkotos
               ("Shrink", "Shrink image"),
873 023e1217 Nikos Skalkotos
               ("View/Modify", "View/Modify image properties"),
874 023e1217 Nikos Skalkotos
               ("Delete", "Delete image properties"),
875 023e1217 Nikos Skalkotos
               ("Exclude", "Exclude various deployment tasks from running")]
876 023e1217 Nikos Skalkotos
877 023e1217 Nikos Skalkotos
    default_item = 0
878 023e1217 Nikos Skalkotos
879 023e1217 Nikos Skalkotos
    actions = {"Sysprep": sysprep,
880 023e1217 Nikos Skalkotos
               "Shrink": shrink,
881 023e1217 Nikos Skalkotos
               "View/Modify": modify_properties,
882 023e1217 Nikos Skalkotos
               "Delete": delete_properties,
883 023e1217 Nikos Skalkotos
               "Exclude": exclude_tasks}
884 023e1217 Nikos Skalkotos
    while 1:
885 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
886 023e1217 Nikos Skalkotos
            text="Choose one of the following or press <Back> to exit.",
887 023e1217 Nikos Skalkotos
            width=WIDTH, choices=choices, cancel="Back", height=13,
888 023e1217 Nikos Skalkotos
            menu_height=len(choices), default_item=choices[default_item][0],
889 023e1217 Nikos Skalkotos
            title="Image Customization Menu")
890 023e1217 Nikos Skalkotos
891 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
892 023e1217 Nikos Skalkotos
            break
893 023e1217 Nikos Skalkotos
        elif choice in actions:
894 023e1217 Nikos Skalkotos
            default_item = [entry[0] for entry in choices].index(choice)
895 023e1217 Nikos Skalkotos
            if actions[choice](session):
896 023e1217 Nikos Skalkotos
                default_item = (default_item + 1) % len(choices)
897 023e1217 Nikos Skalkotos
898 023e1217 Nikos Skalkotos
899 023e1217 Nikos Skalkotos
def main_menu(session):
900 88f83027 Nikos Skalkotos
    """Show the main menu of the program"""
901 023e1217 Nikos Skalkotos
    d = session['dialog']
902 023e1217 Nikos Skalkotos
903 023e1217 Nikos Skalkotos
    update_background_title(session)
904 023e1217 Nikos Skalkotos
905 49c07ce3 Nikos Skalkotos
    choices = [("Customize", "Customize image & cloud deployment options"),
906 49c07ce3 Nikos Skalkotos
               ("Register", "Register image to a cloud"),
907 023e1217 Nikos Skalkotos
               ("Extract", "Dump image to local file system"),
908 023e1217 Nikos Skalkotos
               ("Reset", "Reset everything and start over again"),
909 023e1217 Nikos Skalkotos
               ("Help", "Get help for using snf-image-creator")]
910 023e1217 Nikos Skalkotos
911 023e1217 Nikos Skalkotos
    default_item = "Customize"
912 023e1217 Nikos Skalkotos
913 023e1217 Nikos Skalkotos
    actions = {"Customize": customization_menu, "Register": kamaki_menu,
914 023e1217 Nikos Skalkotos
               "Extract": extract_image}
915 023e1217 Nikos Skalkotos
    while 1:
916 023e1217 Nikos Skalkotos
        (code, choice) = d.menu(
917 023e1217 Nikos Skalkotos
            text="Choose one of the following or press <Exit> to exit.",
918 023e1217 Nikos Skalkotos
            width=WIDTH, choices=choices, cancel="Exit", height=13,
919 023e1217 Nikos Skalkotos
            default_item=default_item, menu_height=len(choices),
920 ffc64d7c Nikos Skalkotos
            title="Image Creator for synnefo (snf-image-creator version %s)" %
921 023e1217 Nikos Skalkotos
                  version)
922 023e1217 Nikos Skalkotos
923 023e1217 Nikos Skalkotos
        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
924 023e1217 Nikos Skalkotos
            if confirm_exit(d):
925 023e1217 Nikos Skalkotos
                break
926 023e1217 Nikos Skalkotos
        elif choice == "Reset":
927 023e1217 Nikos Skalkotos
            if confirm_reset(d):
928 34e7a04a Nikos Skalkotos
                d.infobox("Resetting snf-image-creator. Please wait ...",
929 023e1217 Nikos Skalkotos
                          width=SMALL_WIDTH)
930 023e1217 Nikos Skalkotos
                raise Reset
931 aa04fb4e Nikos Skalkotos
        elif choice == "Help":
932 aa04fb4e Nikos Skalkotos
            d.msgbox("For help, check the online documentation:\n\nhttp://www"
933 aa04fb4e Nikos Skalkotos
                     ".synnefo.org/docs/snf-image-creator/latest/",
934 aa04fb4e Nikos Skalkotos
                     width=WIDTH, title="Help")
935 023e1217 Nikos Skalkotos
        elif choice in actions:
936 023e1217 Nikos Skalkotos
            actions[choice](session)
937 023e1217 Nikos Skalkotos
938 023e1217 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :