summaryrefslogtreecommitdiff
path: root/tuskar_ui/infrastructure/resource_management/racks/forms.py
blob: 265f98f884eb40f97e5236a4322d29fdf2192bb3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# vim: tabstop=4 shiftwidth=4 softtabstop=4

from django.forms import ValidationError
from django.utils.translation import ugettext_lazy as _

from horizon import exceptions
from horizon import forms
from horizon import messages

from tuskar_ui import api

import base64
import csv
import logging
import StringIO

LOG = logging.getLogger(__name__)


class UploadRack(forms.SelfHandlingForm):
    csv_file = forms.FileField(label=_("Choose CSV File"),
                               help_text=("CSV file with rack definitions"),
                               required=False)
    uploaded_data = forms.CharField(widget=forms.HiddenInput(),
                                    required=False)

    def clean_csv_file(self):
        csv_file = self.cleaned_data['csv_file']
        data = csv_file.read() if csv_file else None

        if 'upload' in self.request.POST:
            if not csv_file:
                raise ValidationError(_('CSV file not set.'))
            else:
                try:
                    CSVRack.from_str(data)
                except Exception:
                    LOG.exception("Failed to parse rack CSV file.")
                    raise ValidationError(_('Failed to parse CSV file.'))
        return data

    def clean_uploaded_data(self):
        data = self.cleaned_data['uploaded_data']
        if 'add_racks' in self.request.POST:
            if not data:
                raise ValidationError(_('Upload CSV file first'))
        elif 'upload' in self.request.POST:
            # reset obsolete uploaded data
            self.data['uploaded_data'] = None
        return data

    def handle(self, request, data):
        if 'upload' in self.request.POST:
            # if upload button was pressed, stay on the same page
            # but show content of the CSV file in table
            racks_str = self.cleaned_data['csv_file']
            self.initial['racks'] = CSVRack.from_str(racks_str)
            self.data['uploaded_data'] = base64.b64encode(racks_str)
            return False
        else:
            fails = []
            successes = []
            racks_str = self.cleaned_data['uploaded_data']
            racks = CSVRack.from_str(base64.b64decode(racks_str))
            # get the resource class ids by resource class names
            rclass_ids = dict((rc.name, rc.id) for rc in
                    api.tuskar.ResourceClass.list(request))
            for rack in racks:
                try:
                    api.tuskar.Rack.create(request, rack.name,
                                           rclass_ids[rack.resource_class],
                                           rack.region, rack.subnet)
                    # FIXME: will have to handle nodes once proper attributes
                    # for nodes are added
                    successes.append(rack.name)
                except:
                    LOG.exception("Exception in processing rack CSV file.")
                    fails.append(rack.name)
            if successes:
                messages.success(request,
                                 _('Added %d racks.') % len(successes))
            if fails:
                messages.error(request,
                               _('Failed to add following racks: %s') %
                                   (',').join(fails))
            return True


class CSVRack:
    def __init__(self, **kwargs):
        self.id = kwargs['id']
        self.name = kwargs['name']
        self.resource_class = kwargs['resource_class']
        self.region = kwargs['region']
        self.subnet = kwargs['subnet']
        self.nodes = kwargs['nodes']

    @classmethod
    def from_str(cls, csv_str):
        racks = []
        csvreader = csv.reader(StringIO.StringIO(csv_str), delimiter=',')
        for row in csvreader:
            # ignore empty rows
            if not row:
                continue
            racks.append(cls(id=row[0],
                             name=row[0],
                             resource_class=row[1],
                             subnet=row[2],
                             region=row[3],
                             nodes=row[4].split()))
        return racks

    def nodes_count(self):
        return len(self.nodes)


class UpdateRackStatus(forms.SelfHandlingForm):

    def handle(self, request, data):
        try:
            rack = self.initial.get('rack', None)
            action = request.GET.get('action')

            if action == "provision":
                api.tuskar.Rack.provision(
                    request,
                    rack.id)

                msg = _('Rack "%s" is being provisioned.') % rack.name
            else:
                if action == "start":
                    rack.state = "active"
                elif action == "unprovision":
                    rack.state = "unprovisioned"
                elif action == "reboot":
                    rack.state = "active"
                elif action == "shutdown":
                    rack.state = "off"

                rack = api.tuskar.Rack.update(
                    request,
                    rack.id,
                    {'state': rack.state}
                )

                msg = _('Updated rack "%s" status.') % rack.name
            messages.success(request, msg)
            return True
        except:
            exceptions.handle(request, _("Unable to update Rack status."))