forms.py 11.3 KB
Newer Older
W
wangyong 已提交
1 2
# coding:utf-8
from django import forms
baltery's avatar
baltery 已提交
3
from django.utils.translation import gettext_lazy as _
W
wangyong 已提交
4

baltery's avatar
baltery 已提交
5
from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser
baltery's avatar
baltery 已提交
6 7 8 9
from common.utils import validate_ssh_private_key, ssh_pubkey_gen, ssh_key_gen, get_logger


logger = get_logger(__file__)
W
wangyong 已提交
10 11


baltery's avatar
baltery 已提交
12
class AssetCreateForm(forms.ModelForm):
W
wangyong 已提交
13 14 15
    class Meta:
        model = Asset
        fields = [
baltery's avatar
baltery 已提交
16 17
            'hostname', 'ip', 'public_ip', 'port', 'type', 'comment',
            'admin_user', 'idc', 'groups', 'status', 'env', 'is_active'
baltery's avatar
baltery 已提交
18 19
        ]
        widgets = {
baltery's avatar
baltery 已提交
20 21 22 23 24 25
            'groups': forms.SelectMultiple(
                attrs={'class': 'select2',
                       'data-placeholder': _('Select asset groups')}),
            'admin_user': forms.Select(
                attrs={'class': 'select2',
                       'data-placeholder': _('Select asset admin user')}),
baltery's avatar
baltery 已提交
26 27 28 29
        }
        help_texts = {
            'hostname': '* required',
            'ip': '* required',
baltery's avatar
baltery 已提交
30 31 32 33
            'system_users': _('System user will be granted for user to login '
                              'assets (using ansible create automatic)'),
            'admin_user': _('Admin user should be exist on asset already, '
                            'And have sudo ALL permission'),
baltery's avatar
baltery 已提交
34 35
        }

baltery's avatar
baltery 已提交
36 37 38 39 40
    def clean_admin_user(self):
        if not self.cleaned_data['admin_user']:
            raise forms.ValidationError(_('Select admin user'))
        return self.cleaned_data['admin_user']

baltery's avatar
baltery 已提交
41

baltery's avatar
baltery 已提交
42
class AssetUpdateForm(forms.ModelForm):
baltery's avatar
baltery 已提交
43 44 45 46 47
    class Meta:
        model = Asset
        fields = [
            'hostname', 'ip', 'port', 'groups', 'admin_user', 'idc', 'is_active',
            'type', 'env', 'status', 'public_ip', 'remote_card_ip', 'cabinet_no',
baltery's avatar
baltery 已提交
48
            'cabinet_pos', 'number', 'comment'
W
wangyong 已提交
49
        ]
W
wangyong 已提交
50
        widgets = {
baltery's avatar
baltery 已提交
51 52 53 54 55 56
            'groups': forms.SelectMultiple(
                attrs={'class': 'select2',
                       'data-placeholder': _('Select asset groups')}),
            'admin_user': forms.Select(
                attrs={'class': 'select2',
                       'data-placeholder': _('Select asset admin user')}),
baltery's avatar
baltery 已提交
57 58 59 60
        }
        help_texts = {
            'hostname': '* required',
            'ip': '* required',
baltery's avatar
baltery 已提交
61 62 63 64
            'system_users': _('System user will be granted for user '
                              'to login assets (using ansible create automatic)'),
            'admin_user': _('Admin user should be exist on asset '
                            'already, And have sudo ALL permission'),
W
wangyong 已提交
65 66
        }

W
wangyong 已提交
67

baltery's avatar
baltery 已提交
68
class AssetBulkUpdateForm(forms.ModelForm):
baltery's avatar
baltery 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82
    assets = forms.MultipleChoiceField(
        required=True,
        help_text='* required',
        label=_('Select assets'),
        widget=forms.SelectMultiple(
            attrs={
                'class': 'select2',
                'data-placeholder': _('Select assets')
            }
        )
    )
    port = forms.IntegerField(min_value=1, max_value=65535,
                              required=False, label=_('Port'))

baltery's avatar
baltery 已提交
83 84 85
    class Meta:
        model = Asset
        fields = [
baltery's avatar
baltery 已提交
86
            'assets', 'port', 'groups', 'admin_user', 'idc',
baltery's avatar
baltery 已提交
87 88 89 90 91 92 93 94 95 96 97
            'type', 'env', 'status',
        ]
        widgets = {
            'groups': forms.SelectMultiple(
                attrs={'class': 'select2',
                       'data-placeholder': _('Select asset groups')}),
            'admin_user': forms.Select(
                attrs={'class': 'select2',
                       'data-placeholder': _('Select asset admin user')}),
        }

baltery's avatar
baltery 已提交
98 99 100 101 102 103 104 105 106 107 108
    def save(self, commit=True):
        cleaned_data = {k: v for k, v in self.cleaned_data.items() if v is not None}
        assets_id = cleaned_data.pop('assets')
        groups = cleaned_data.pop('groups')
        assets = Asset.objects.filter(id__in=assets_id)
        assets.update(**cleaned_data)
        if groups:
            for asset in assets:
                asset.groups.set(groups)
        return assets

baltery's avatar
baltery 已提交
109

W
wangyong 已提交
110
class AssetGroupForm(forms.ModelForm):
baltery's avatar
baltery 已提交
111
    # See AdminUserForm comment same it
baltery's avatar
baltery 已提交
112 113 114 115 116 117 118
    assets = forms.ModelMultipleChoiceField(
        queryset=Asset.objects.all(),
        label=_('Asset'),
        required=False,
        widget=forms.SelectMultiple(
            attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
        )
baltery's avatar
baltery 已提交
119 120

    def __init__(self, *args, **kwargs):
baltery's avatar
baltery 已提交
121
        if kwargs.get('instance', None):
baltery's avatar
baltery 已提交
122 123 124 125 126 127 128 129 130 131
            initial = kwargs.get('initial', {})
            initial['assets'] = kwargs['instance'].assets.all()
        super(AssetGroupForm, self).__init__(*args, **kwargs)

    def _save_m2m(self):
        super(AssetGroupForm, self)._save_m2m()
        assets = self.cleaned_data['assets']
        self.instance.assets.clear()
        self.instance.assets.add(*tuple(assets))

W
wangyong 已提交
132 133 134
    class Meta:
        model = AssetGroup
        fields = [
baltery's avatar
baltery 已提交
135
            "name", "comment",
W
wangyong 已提交
136
        ]
baltery's avatar
baltery 已提交
137 138 139
        help_texts = {
            'name': '* required',
        }
W
wangyong 已提交
140 141


baltery's avatar
Add idc  
baltery 已提交
142
class IDCForm(forms.ModelForm):
baltery's avatar
baltery 已提交
143
    # See AdminUserForm comment same it
baltery's avatar
baltery 已提交
144 145 146 147 148 149 150
    assets = forms.ModelMultipleChoiceField(
        queryset=Asset.objects.all(),
        label=_('Asset'),
        required=False,
        widget=forms.SelectMultiple(
            attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
        )
baltery's avatar
Add idc  
baltery 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163

    def __init__(self, *args, **kwargs):
        if kwargs.get('instance'):
            initial = kwargs.get('initial', {})
            initial['assets'] = kwargs['instance'].assets.all()
        super(IDCForm, self).__init__(*args, **kwargs)

    def _save_m2m(self):
        super(IDCForm, self)._save_m2m()
        assets = self.cleaned_data['assets']
        self.instance.assets.clear()
        self.instance.assets.add(*tuple(assets))

W
wangyong 已提交
164 165
    class Meta:
        model = IDC
X
xiaokong1937@gmail.com 已提交
166 167
        fields = ['name', "bandwidth", "operator", 'contact',
                  'phone', 'address', 'intranet', 'extranet', 'comment']
W
wangyong 已提交
168
        widgets = {
baltery's avatar
Add idc  
baltery 已提交
169
            'name': forms.TextInput(attrs={'placeholder': _('Name')}),
江世峰 已提交
170 171 172 173
            'intranet': forms.Textarea(
                attrs={'placeholder': 'IP段之间用逗号隔开,如:192.168.1.0/24,192.168.1.0/24'}),
            'extranet': forms.Textarea(
                attrs={'placeholder': 'IP段之间用逗号隔开,如:201.1.32.1/24,202.2.32.1/24'})
W
wangyong 已提交
174
        }
baltery's avatar
baltery 已提交
175 176 177
        help_texts = {
            'name': '* required'
        }
baltery's avatar
baltery 已提交
178 179


baltery's avatar
baltery 已提交
180
class AdminUserForm(forms.ModelForm):
baltery's avatar
baltery 已提交
181
    # Form field name can not start with `_`, so redefine it,
baltery's avatar
baltery 已提交
182 183
    password = forms.CharField(
        widget=forms.PasswordInput, max_length=100,
baltery's avatar
baltery 已提交
184
        strip=True, required=False,
baltery's avatar
baltery 已提交
185 186
        help_text=_('If also set private key, use that first'),
    )
baltery's avatar
baltery 已提交
187
    # Need use upload private key file except paste private key content
baltery's avatar
baltery 已提交
188
    private_key_file = forms.FileField(required=False)
baltery's avatar
baltery 已提交
189

baltery's avatar
baltery 已提交
190
    def save(self, commit=True):
baltery's avatar
baltery 已提交
191
        # Because we define custom field, so we need rewrite :method: `save`
baltery's avatar
baltery 已提交
192 193
        admin_user = super(AdminUserForm, self).save(commit=commit)
        password = self.cleaned_data['password']
baltery's avatar
baltery 已提交
194
        private_key = self.cleaned_data['private_key_file']
baltery's avatar
baltery 已提交
195 196 197

        if password:
            admin_user.password = password
baltery's avatar
baltery 已提交
198
        if private_key:
baltery's avatar
baltery 已提交
199
            public_key = ssh_pubkey_gen(private_key)
baltery's avatar
baltery 已提交
200 201
            admin_user.private_key = private_key
            admin_user.public_key = public_key
baltery's avatar
baltery 已提交
202
        admin_user.save()
baltery's avatar
baltery 已提交
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
        return admin_user

    def clean_private_key_file(self):
        private_key_file = self.cleaned_data['private_key_file']
        if private_key_file:
            private_key = private_key_file.read()
            if not validate_ssh_private_key(private_key):
                raise forms.ValidationError(_('Invalid private key'))
            return private_key
        return private_key_file

    def clean(self):
        password = self.cleaned_data['password']
        private_key_file = self.cleaned_data.get('private_key_file', '')

baltery's avatar
baltery 已提交
218 219 220
        if not self.instance and not (password or private_key_file):
            raise forms.ValidationError(
                _('Password and private key file must be input one'))
baltery's avatar
baltery 已提交
221

baltery's avatar
baltery 已提交
222
    class Meta:
baltery's avatar
baltery 已提交
223
        model = AdminUser
X
xiaokong1937@gmail.com 已提交
224 225
        fields = ['name', 'username', 'password',
                  'private_key_file', 'comment']
baltery's avatar
baltery 已提交
226 227
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': _('Name')}),
baltery's avatar
baltery 已提交
228 229 230 231 232 233 234
            'username': forms.TextInput(attrs={'placeholder': _('Username')}),
        }
        help_texts = {
            'name': '* required',
            'username': '* required',
        }

baltery's avatar
baltery 已提交
235 236 237

class SystemUserForm(forms.ModelForm):
    # Admin user assets define, let user select, save it in form not in view
baltery's avatar
baltery 已提交
238
    auto_generate_key = forms.BooleanField(initial=True, required=False)
baltery's avatar
baltery 已提交
239
    # Form field name can not start with `_`, so redefine it,
baltery's avatar
baltery 已提交
240
    password = forms.CharField(widget=forms.PasswordInput, required=False,
baltery's avatar
baltery 已提交
241
                               max_length=100, strip=True)
baltery's avatar
baltery 已提交
242 243 244 245 246 247 248 249 250 251
    # Need use upload private key file except paste private key content
    private_key_file = forms.FileField(required=False)

    def __init__(self, *args, **kwargs):
        super(SystemUserForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        # Because we define custom field, so we need rewrite :method: `save`
        system_user = super(SystemUserForm, self).save(commit=commit)
        password = self.cleaned_data['password']
baltery's avatar
baltery 已提交
252
        private_key_file = self.cleaned_data.get('private_key_file')
baltery's avatar
baltery 已提交
253

baltery's avatar
baltery 已提交
254 255 256
        if system_user.auth_method == 'P':
            if password:
                system_user.password = password
baltery's avatar
baltery 已提交
257 258 259 260 261 262 263 264 265
        elif system_user.auth_method == 'K':
            if self.cleaned_data['auto_generate_key']:
                private_key, public_key = ssh_key_gen(username=system_user.name)
                logger.info('Generate private key and public key')
            else:
                private_key = private_key_file.read().strip()
                public_key = ssh_pubkey_gen(private_key=private_key)
            system_user.private_key = private_key
            system_user.public_key = public_key
baltery's avatar
baltery 已提交
266 267 268
        system_user.save()
        return self.instance

baltery's avatar
baltery 已提交
269 270 271 272 273 274 275 276 277
    def clean_private_key_file(self):
        if self.data['auth_method'] == 'K' and \
                not self.cleaned_data['auto_generate_key']:
            if not self.cleaned_data['private_key_file']:
                raise forms.ValidationError(_('Private key required'))
            else:
                key_string = self.cleaned_data['private_key_file'].read()
                self.cleaned_data['private_key_file'].seek(0)
                if not validate_ssh_private_key(key_string):
baltery's avatar
baltery 已提交
278
                    raise forms.ValidationError(_('Invalid private key'))
baltery's avatar
baltery 已提交
279 280 281 282 283 284 285
        return self.cleaned_data['private_key_file']

    def clean_password(self):
        if self.data['auth_method'] == 'P':
            if not self.cleaned_data.get('password'):
                raise forms.ValidationError(_('Password required'))
        return self.cleaned_data['password']
baltery's avatar
baltery 已提交
286

baltery's avatar
baltery 已提交
287 288 289
    class Meta:
        model = SystemUser
        fields = [
baltery's avatar
baltery 已提交
290 291
            'name', 'username', 'protocol', 'auto_generate_key', 'password',
            'private_key_file', 'auth_method', 'auto_push', 'sudo',
292
            'comment', 'shell'
baltery's avatar
baltery 已提交
293 294 295 296 297 298 299 300
        ]
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': _('Name')}),
            'username': forms.TextInput(attrs={'placeholder': _('Username')}),
        }
        help_texts = {
            'name': '* required',
            'username': '* required',
baltery's avatar
baltery 已提交
301
            'auto_push': 'Auto push system user to asset',
江世峰 已提交
302 303
        }

baltery's avatar
baltery 已提交
304

baltery's avatar
baltery 已提交
305
class FileForm(forms.Form):
306
    file = forms.FileField()