Statistics
| Branch: | Tag: | Revision:

root / image_creator / dialog_wizard.py @ fbdf1d8f

History | View | Annotate | Download (7.2 kB)

1 09ed3d46 Nikos Skalkotos
#!/usr/bin/env python
2 09ed3d46 Nikos Skalkotos
3 09ed3d46 Nikos Skalkotos
# Copyright 2012 GRNET S.A. All rights reserved.
4 09ed3d46 Nikos Skalkotos
#
5 09ed3d46 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
6 09ed3d46 Nikos Skalkotos
# without modification, are permitted provided that the following
7 09ed3d46 Nikos Skalkotos
# conditions are met:
8 09ed3d46 Nikos Skalkotos
#
9 09ed3d46 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
10 09ed3d46 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
11 09ed3d46 Nikos Skalkotos
#      disclaimer.
12 09ed3d46 Nikos Skalkotos
#
13 09ed3d46 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
14 09ed3d46 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
15 09ed3d46 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
16 09ed3d46 Nikos Skalkotos
#      provided with the distribution.
17 09ed3d46 Nikos Skalkotos
#
18 09ed3d46 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 09ed3d46 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 09ed3d46 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 09ed3d46 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 09ed3d46 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 09ed3d46 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 09ed3d46 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 09ed3d46 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 09ed3d46 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 09ed3d46 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 09ed3d46 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 09ed3d46 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
30 09ed3d46 Nikos Skalkotos
#
31 09ed3d46 Nikos Skalkotos
# The views and conclusions contained in the software and
32 09ed3d46 Nikos Skalkotos
# documentation are those of the authors and should not be
33 09ed3d46 Nikos Skalkotos
# interpreted as representing official policies, either expressed
34 09ed3d46 Nikos Skalkotos
# or implied, of GRNET S.A.
35 09ed3d46 Nikos Skalkotos
36 09ed3d46 Nikos Skalkotos
import dialog
37 fbdf1d8f Nikos Skalkotos
import time
38 fbdf1d8f Nikos Skalkotos
import StringIO
39 09ed3d46 Nikos Skalkotos
40 fbdf1d8f Nikos Skalkotos
from image_creator.kamaki_wrapper import Kamaki, ClientError
41 fbdf1d8f Nikos Skalkotos
from image_creator.util import MD5, FatalError
42 fbdf1d8f Nikos Skalkotos
from image_creator.output.cli import OutputWthProgress
43 09ed3d46 Nikos Skalkotos
44 3c33e68a Nikos Skalkotos
PAGE_WIDTH = 70
45 09ed3d46 Nikos Skalkotos
46 09ed3d46 Nikos Skalkotos
47 3c33e68a Nikos Skalkotos
class Wizard:
48 3c33e68a Nikos Skalkotos
    def __init__(self, session):
49 3c33e68a Nikos Skalkotos
        self.session = session
50 3c33e68a Nikos Skalkotos
        self.pages = []
51 3c33e68a Nikos Skalkotos
        self.session['wizard'] = {}
52 3c33e68a Nikos Skalkotos
53 3c33e68a Nikos Skalkotos
    def add_page(self, page):
54 3c33e68a Nikos Skalkotos
        self.pages.append(page)
55 09ed3d46 Nikos Skalkotos
56 09ed3d46 Nikos Skalkotos
    def run(self):
57 3c33e68a Nikos Skalkotos
        idx = 0
58 3c33e68a Nikos Skalkotos
        while True:
59 3c33e68a Nikos Skalkotos
            idx += self.pages[idx].run(self.session, idx, len(self.pages))
60 09ed3d46 Nikos Skalkotos
61 3c33e68a Nikos Skalkotos
            if idx >= len(self.pages):
62 3c33e68a Nikos Skalkotos
                break
63 09ed3d46 Nikos Skalkotos
64 3c33e68a Nikos Skalkotos
            if idx < 0:
65 3c33e68a Nikos Skalkotos
                return False
66 3c33e68a Nikos Skalkotos
        return True
67 09ed3d46 Nikos Skalkotos
68 09ed3d46 Nikos Skalkotos
69 3c33e68a Nikos Skalkotos
class WizardPage:
70 3c33e68a Nikos Skalkotos
    NEXT = 1
71 3c33e68a Nikos Skalkotos
    PREV = -1
72 fbdf1d8f Nikos Skalkotos
    EXIT = -255
73 fbdf1d8f Nikos Skalkotos
74 fbdf1d8f Nikos Skalkotos
    def run(self, session, index, total):
75 fbdf1d8f Nikos Skalkotos
        raise NotImplementedError
76 fbdf1d8f Nikos Skalkotos
77 fbdf1d8f Nikos Skalkotos
78 fbdf1d8f Nikos Skalkotos
class WizardInputPage(WizardPage):
79 09ed3d46 Nikos Skalkotos
80 3c33e68a Nikos Skalkotos
    def __init__(self, name, message, **kargs):
81 3c33e68a Nikos Skalkotos
        self.name = name
82 3c33e68a Nikos Skalkotos
        self.message = message
83 3c33e68a Nikos Skalkotos
        self.title = kargs['title'] if 'title' in kargs else ''
84 3c33e68a Nikos Skalkotos
        self.init_value = kargs['init'] if 'init' in kargs else ''
85 3c33e68a Nikos Skalkotos
        self.allow_empty = kargs['empty'] if 'empty' in kargs else False
86 09ed3d46 Nikos Skalkotos
87 3c33e68a Nikos Skalkotos
    def run(self, session, index, total):
88 3c33e68a Nikos Skalkotos
        d = session['dialog']
89 3c33e68a Nikos Skalkotos
        w = session['wizard']
90 09ed3d46 Nikos Skalkotos
91 3c33e68a Nikos Skalkotos
        init = w[self.name] if self.name in w else self.init_value
92 3c33e68a Nikos Skalkotos
        while True:
93 3c33e68a Nikos Skalkotos
            (code, answer) = d.inputbox(self.message, init=init,
94 3c33e68a Nikos Skalkotos
                width=PAGE_WIDTH, ok_label="Next", cancel="Back",
95 3c33e68a Nikos Skalkotos
                title="(%d/%d) %s" % (index + 1, total, self.title))
96 09ed3d46 Nikos Skalkotos
97 09ed3d46 Nikos Skalkotos
            if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
98 09ed3d46 Nikos Skalkotos
                return self.PREV
99 09ed3d46 Nikos Skalkotos
100 3c33e68a Nikos Skalkotos
            value = answer.strip()
101 3c33e68a Nikos Skalkotos
            if len(value) == 0 and self.allow_empty is False:
102 3c33e68a Nikos Skalkotos
                d.msgbox("The value cannot be empty!", width=PAGE_WIDTH)
103 3c33e68a Nikos Skalkotos
                continue
104 3c33e68a Nikos Skalkotos
            w[self.name] = value
105 09ed3d46 Nikos Skalkotos
            break
106 09ed3d46 Nikos Skalkotos
107 09ed3d46 Nikos Skalkotos
        return self.NEXT
108 09ed3d46 Nikos Skalkotos
109 09ed3d46 Nikos Skalkotos
110 fbdf1d8f Nikos Skalkotos
class WizardYesNoPage(WizardPage):
111 fbdf1d8f Nikos Skalkotos
112 fbdf1d8f Nikos Skalkotos
    def __init__(self, message, **kargs):
113 fbdf1d8f Nikos Skalkotos
        self.message = message
114 fbdf1d8f Nikos Skalkotos
        self.title = kargs['title'] if 'title' in kargs else ''
115 fbdf1d8f Nikos Skalkotos
116 fbdf1d8f Nikos Skalkotos
    def run(self, session, index, total):
117 fbdf1d8f Nikos Skalkotos
        d = session['dialog']
118 fbdf1d8f Nikos Skalkotos
119 fbdf1d8f Nikos Skalkotos
        while True:
120 fbdf1d8f Nikos Skalkotos
            ret = d.yesno(self.message, width=PAGE_WIDTH, ok_label="Yes",
121 fbdf1d8f Nikos Skalkotos
                    cancel="Back", extra_button=1, extra_label="Quit",
122 fbdf1d8f Nikos Skalkotos
                    title="(%d/%d) %s" % (index + 1, total, self.title))
123 fbdf1d8f Nikos Skalkotos
124 fbdf1d8f Nikos Skalkotos
            if ret == d.DIALOG_CANCEL:
125 fbdf1d8f Nikos Skalkotos
                return self.PREV
126 fbdf1d8f Nikos Skalkotos
            elif ret == d.DIALOG_EXTRA:
127 fbdf1d8f Nikos Skalkotos
                return self.EXIT
128 fbdf1d8f Nikos Skalkotos
            elif ret == d.DIALOG_OK:
129 fbdf1d8f Nikos Skalkotos
                return self.NEXT
130 fbdf1d8f Nikos Skalkotos
131 fbdf1d8f Nikos Skalkotos
132 09ed3d46 Nikos Skalkotos
def wizard(session):
133 09ed3d46 Nikos Skalkotos
134 fbdf1d8f Nikos Skalkotos
    name = WizardInputPage("ImageName", "Please provide a name for the image:",
135 3c33e68a Nikos Skalkotos
                      title="Image Name", init=session['device'].distro)
136 fbdf1d8f Nikos Skalkotos
    descr = WizardInputPage("ImageDescription",
137 3c33e68a Nikos Skalkotos
        "Please provide a description for the image:",
138 3c33e68a Nikos Skalkotos
        title="Image Description", empty=True,
139 3c33e68a Nikos Skalkotos
        init=session['metadata']['DESCRIPTION'] if 'DESCRIPTION' in
140 3c33e68a Nikos Skalkotos
        session['metadata'] else '')
141 fbdf1d8f Nikos Skalkotos
    account = WizardInputPage("account",
142 3c33e68a Nikos Skalkotos
        "Please provide your ~okeanos account e-mail:",
143 3c33e68a Nikos Skalkotos
        title="~okeanos account information", init=Kamaki.get_account())
144 fbdf1d8f Nikos Skalkotos
    token = WizardInputPage("token",
145 3c33e68a Nikos Skalkotos
        "Please provide your ~okeanos account token:",
146 3c33e68a Nikos Skalkotos
        title="~okeanos account token", init=Kamaki.get_token())
147 3c33e68a Nikos Skalkotos
148 fbdf1d8f Nikos Skalkotos
    msg = "Do you wish to continue with the image extraction process?"
149 fbdf1d8f Nikos Skalkotos
    proceed = WizardYesNoPage(msg, title="Confirmation")
150 fbdf1d8f Nikos Skalkotos
151 3c33e68a Nikos Skalkotos
    w = Wizard(session)
152 fbdf1d8f Nikos Skalkotos
153 3c33e68a Nikos Skalkotos
    w.add_page(name)
154 3c33e68a Nikos Skalkotos
    w.add_page(descr)
155 3c33e68a Nikos Skalkotos
    w.add_page(account)
156 3c33e68a Nikos Skalkotos
    w.add_page(token)
157 fbdf1d8f Nikos Skalkotos
    w.add_page(proceed)
158 fbdf1d8f Nikos Skalkotos
159 fbdf1d8f Nikos Skalkotos
    if w.run():
160 fbdf1d8f Nikos Skalkotos
        extract_image(session)
161 fbdf1d8f Nikos Skalkotos
    else:
162 fbdf1d8f Nikos Skalkotos
        return False
163 fbdf1d8f Nikos Skalkotos
164 fbdf1d8f Nikos Skalkotos
    return True
165 fbdf1d8f Nikos Skalkotos
166 fbdf1d8f Nikos Skalkotos
167 fbdf1d8f Nikos Skalkotos
def extract_image(session):
168 fbdf1d8f Nikos Skalkotos
    disk = session['disk']
169 fbdf1d8f Nikos Skalkotos
    device = session['device']
170 fbdf1d8f Nikos Skalkotos
    snapshot = session['snapshot']
171 fbdf1d8f Nikos Skalkotos
    image_os = session['image_os']
172 fbdf1d8f Nikos Skalkotos
    wizard = session['wizard']
173 fbdf1d8f Nikos Skalkotos
174 fbdf1d8f Nikos Skalkotos
    out = OutputWthProgress(True)
175 fbdf1d8f Nikos Skalkotos
    #Initialize the output
176 fbdf1d8f Nikos Skalkotos
    disk.out = out
177 fbdf1d8f Nikos Skalkotos
    device.out = out
178 fbdf1d8f Nikos Skalkotos
    image_os.out = out
179 fbdf1d8f Nikos Skalkotos
180 fbdf1d8f Nikos Skalkotos
    out.output()
181 fbdf1d8f Nikos Skalkotos
182 fbdf1d8f Nikos Skalkotos
    #Sysprep
183 fbdf1d8f Nikos Skalkotos
    device.mount(False)
184 fbdf1d8f Nikos Skalkotos
    image_os.do_sysprep()
185 fbdf1d8f Nikos Skalkotos
    metadata = image_os.meta
186 fbdf1d8f Nikos Skalkotos
    device.umount()
187 fbdf1d8f Nikos Skalkotos
188 fbdf1d8f Nikos Skalkotos
    #Shrink
189 fbdf1d8f Nikos Skalkotos
    size = device.shrink()
190 fbdf1d8f Nikos Skalkotos
191 fbdf1d8f Nikos Skalkotos
    #MD5
192 fbdf1d8f Nikos Skalkotos
    md5 = MD5(out)
193 fbdf1d8f Nikos Skalkotos
    checksum = md5.compute(snapshot, size)
194 fbdf1d8f Nikos Skalkotos
195 fbdf1d8f Nikos Skalkotos
    #Metadata
196 fbdf1d8f Nikos Skalkotos
    metastring = '\n'.join(
197 fbdf1d8f Nikos Skalkotos
        ['%s=%s' % (key, value) for (key, value) in metadata.items()])
198 fbdf1d8f Nikos Skalkotos
    metastring += '\n'
199 fbdf1d8f Nikos Skalkotos
200 fbdf1d8f Nikos Skalkotos
    out.output()
201 fbdf1d8f Nikos Skalkotos
    try:
202 fbdf1d8f Nikos Skalkotos
        out.output("Uploading image to pithos:")
203 fbdf1d8f Nikos Skalkotos
        kamaki = Kamaki(wizard['account'], wizard['token'], out)
204 fbdf1d8f Nikos Skalkotos
205 fbdf1d8f Nikos Skalkotos
        name = "%s-%s.diskdump" % (wizard['ImageName'],
206 fbdf1d8f Nikos Skalkotos
                                   time.strftime("%Y%m%d%H%M"))
207 fbdf1d8f Nikos Skalkotos
        pithos_file = ""
208 fbdf1d8f Nikos Skalkotos
        with open(snapshot, 'rb') as f:
209 fbdf1d8f Nikos Skalkotos
            pithos_file = kamaki.upload(f, size, name,
210 fbdf1d8f Nikos Skalkotos
                                         "(1/4)  Calculating block hashes",
211 fbdf1d8f Nikos Skalkotos
                                         "(2/4)  Uploading missing blocks")
212 fbdf1d8f Nikos Skalkotos
213 fbdf1d8f Nikos Skalkotos
        out.output("(3/4)  Uploading metadata file...", False)
214 fbdf1d8f Nikos Skalkotos
        kamaki.upload(StringIO.StringIO(metastring), size=len(metastring),
215 fbdf1d8f Nikos Skalkotos
                      remote_path="%s.%s" % (name, 'meta'))
216 fbdf1d8f Nikos Skalkotos
        out.success('done')
217 fbdf1d8f Nikos Skalkotos
        out.output("(4/4)  Uploading md5sum file...", False)
218 fbdf1d8f Nikos Skalkotos
        md5sumstr = '%s %s\n' % (checksum, name)
219 fbdf1d8f Nikos Skalkotos
        kamaki.upload(StringIO.StringIO(md5sumstr), size=len(md5sumstr),
220 fbdf1d8f Nikos Skalkotos
                      remote_path="%s.%s" % (name, 'md5sum'))
221 fbdf1d8f Nikos Skalkotos
        out.success('done')
222 fbdf1d8f Nikos Skalkotos
        out.output()
223 fbdf1d8f Nikos Skalkotos
224 fbdf1d8f Nikos Skalkotos
        out.output('Registring image to ~okeanos...', False)
225 fbdf1d8f Nikos Skalkotos
        kamaki.register(wizard['ImageName'], pithos_file, metadata)
226 fbdf1d8f Nikos Skalkotos
        out.success('done')
227 fbdf1d8f Nikos Skalkotos
        out.output()
228 fbdf1d8f Nikos Skalkotos
    except ClientError as e:
229 fbdf1d8f Nikos Skalkotos
        raise FatalError("Pithos client: %d %s" % (e.status, e.message))
230 09ed3d46 Nikos Skalkotos
231 09ed3d46 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :